Bean作用域
- singleton作用域(单例,限定在一个上下文环境中)
- prototype作用域(多例)
- Web环境作用域
- request作用域
- session作用域
- application作用域
- websocket作用域
- 自定义作用域
- SimpleThreadScope作用域
<!-- 单例 默认singleton --> <bean id="bean" class="com.demo.ioc.Bean"/> <!-- 多例 --> <bean id="bean" class="com.demo.ioc.Bean" scope="prototype"/>
总结
配置
<bean id="bean2" class="com.demo.ioc.Bean2" scope="prototype"/>
<bean id="bean1" class="com.demo.ioc.Bean1">
<property name="bean2" ref="bean2"/>
</bean>
方法注入
场景:
Bean1是singleton, Bean2是prototype, Bean1依赖于Bean2
我们希望每次调用Bean1某个方法时候,该方法每次拿到Bean2都是新的实例
package com.demo.ioc; public class Bean2 { } package com.demo.ioc; public abstract class Bean1 { protected abstract Bean2 createBean2(); } <bean id="bean2" class="com.demo.ioc.Bean2" scope="prototype"/> <bean id="bean1" class="com.demo.ioc.Bean1" scope="singleton"> <lookup-method name="createBean2" bean="bean2"/> </bean>
Web环境作用域
项目结构
$ tree . ├── pom.xml └── src └── main ├── java │ └── com │ └── demo │ ├── ApplicationController.java │ ├── RequestController.java │ └── SessionController.java ├── resources │ └── spring.xml └── webapp └── WEB-INF └── web.xml
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>spring-mvc</groupId> <artifactId>com.demo</artifactId> <version>1.0-SNAPSHOT</version> <!--打包方式为war--> <packaging>war</packaging> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.1.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.1.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.1.3.RELEASE</version> </dependency> </dependencies> </project>
web.xml
<?xml version="1.0" encoding="utf-8" ?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" > <!-- 建立SpringWeb上下文环境--> <servlet> <servlet-name>SpringServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>SpringServlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
RequestController.java
package com.demo; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class RequestController { @RequestMapping("/request") @ResponseBody public String test(){ return this.toString(); } }
SessionController.java
package com.demo; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class SessionController { @RequestMapping("/session") @ResponseBody public String test(){ return this.toString(); } }
ApplicationController.java
package com.demo; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class ApplicationController { @RequestMapping("/application") @ResponseBody public String test(){ return this.toString(); } }
总结
reuqest:每个request请求都会创建一个单独的实例。
session:每个session都会创建一个单独的实例。
application:每个sercletContext都会创建一个单独的实例。
websocket:每个websocket链接都会创建一个单独的实例。
自定义作用域
双例模式
package com.demo.ioc; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.config.Scope; import java.util.Map; import java.util.Random; import java.util.concurrent.ConcurrentHashMap; /** * 自定义作用域 * 实现双例模式(每一个Bean对应两个实例) */ public class MyScope implements Scope { Map<String, Object> map1 = new ConcurrentHashMap<>(); Map<String, Object> map2 = new ConcurrentHashMap<>(); @Override public Object get(String name, ObjectFactory<?> objectFactory) { //先从map1取 if (!map1.containsKey(name)) { Object obj = objectFactory.getObject(); map1.put(name, obj); return obj; } //再从map2取 if (!map2.containsKey(name)) { Object obj = objectFactory.getObject(); map2.put(name, obj); return obj; } // 如果map1和map2中都存在则随机返回 int i = new Random().nextInt(2); if (i == 0) { return map1.get(name); } else { return map2.get(name); } } @Override public Object remove(String name) { // 和添加顺序正好相反 if(map2.containsKey(name)){ Object obj = map2.get(name); map2.remove(name); return obj; } if(map1.containsKey(name)){ Object obj = map1.get(name); map1.remove(name); return obj; } return null; } @Override public void registerDestructionCallback(String name, Runnable callback) { } @Override public Object resolveContextualObject(String key) { return null; } @Override public String getConversationId() { return null; } } package com.demo.ioc; public class Bean { }
<?xml version="1.0" encoding="utf-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd"> <bean id="myScope" class="com.demo.ioc.MyScope"/> <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="myScope" value-ref="myScope"/> </map> </property> </bean> <bean class="com.demo.ioc.Bean" id="bean" scope="myScope"/> </beans>
测试
package com.demo.ioc; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class BeanTest { @Test public void testBean(){ // 获取上下文 ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); for (int i = 0; i < 10; i++) { Bean bean = context.getBean("bean", Bean.class); System.out.println(bean); } } }