bean的作用域
加紧学习,抓住中心,宁精勿杂,宁专勿多。 ——***
Spring作用域
在默认情况下,Spring上下文中所有bean都是作为以单例(singleton)的形式创建的。有时候,你所使用的类是易变(mutable),在这种情况下将bean声明为单例是不安全的。
Spring定义了多种作用域,可以基于这些作用域创建bean,包括:
1) 单例(Singleton):在整个应用中,只创建bean的一个实例。
2) 原型(Prototype):每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例。
3) 会话(Session):在Web应用中,为每个会话创建一个bean实例。
4) 请求(Request):在Web应用中,为每个请求创建一个bean 实例。
设置原型作用域(Prototype)
1.在Java配置中使用@Scope注解,它可以与@Component或@Bean一起使用。
package chapter3.practice4; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @Component @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class Ball { /** * @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) 等同于 @Scope("prototype") * @Scope(ConfigurableBeanFactory.) 等同于 @Scope("prototype") */ }
package chapter3.practice4; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; @Configuration public class BallConfig { @Bean @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public Ball ball() { return new Ball(); } }
2.在XML配置中,可以通过<bean>元素的scope属性*设置作用域。
<?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:aop="http://www.springframework.org/schema/aop" xmlns:c="http://www.springframework.org/schema/c" xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee" xsi:schemaLocation="http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd"> <bean scope="prototype" id="ball" class="chapter3.practice4.Ball"></bean> </beans>
使用会话和请求作用域
1.在Web应用中,如果能够实例化在会话和请求范围内共享的bean,是非常有意义的。在典型的电子商务中,购物车bean指定会话作用域是最为合适的,因为它与给定用户关联性最大。如下,在Java配置中可以使用@Scope注解指定会话作用域:
package chapter3.practice4; import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.ScopedProxyMode; import org.springframework.stereotype.Component; import org.springframework.web.context.WebApplicationContext; @Component @Scope( value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.INTERFACES ) public class ShoppingCart { }
1) value属性设置为WebApplicationContext.SCOPE_SESSION(Session),它会告诉Spring为Web应用中每个会话创建一个ShoppingCart实例,在当前会话中,这个ShoppingCart实例实际上相当于单例的。
2) proxyMode属性设置为ScopedProxyMode.INTERFACES,这个属性解决了将会话或请求作用域的bean注入到单例bean中所遇到的问题:
package chapter3.practice4; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class ShopService { private ShoppingCart shoppingCart; @Autowired public void setShoppingCart(ShoppingCart shoppingCart) { this.shoppingCart = shoppingCart; } }
① ShopService bean的作用域默认是单例,会在Spring应用上下文加载的时候创建。当它创建的时候,Spring会试图将ShoppingCart bean注入到setShoppingCart()方法中,但是ShoppingCart作用域是会话域,此时并没有创建,只有当某个用户进入系统,创建了会话之后,才会创建ShoppingCart bean。
② 系统中有多个用户,每个用户都将会有一个ShoppingCart实例,我们不想注入某个固定的ShoppingCart实例到ShopService中,而是希望注入的ShoppingCart实例恰好就是当前会话的实例。
设定@Scope的proxyMode属性后,Spring不会将实际的ShoppingCart实例注入到ShopService,而是注入一个ShoppingCart实例的代理,当ShopService调用ShoppingCart的方法时,代理会对其进行懒解析并将调用委托给会话作用域内真正的ShoppingCart实例。
代理模式有两种:
(1) 基于接口的代理(ScopedProxyMode.INTERFACES),即ShoppingCart是接口,Spring就会创建基于接口的代理。
(2) 基于类的代理(ScopedProxyMode.TARGET_CLASS),即ShoppingCart是一个具体的类,Spring会使用CGLib*生成基于类的代理。
2.在XML中声明会话或请求作用域的bean,设置<bean>元素的scope属性;要设置代理模式,使用Spring aop命名空间的一个新元素:<aop:scoped-proxy>元素。
<?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:aop="http://www.springframework.org/schema/aop" xmlns:c="http://www.springframework.org/schema/c" xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee" xsi:schemaLocation="http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd"> <bean id="cart" class="chapter3.practice4.ShoppingCart" scope="session"> <aop:scoped-proxy/> </bean> </beans>
值得注意的是:<aop:scoped-proxy>默认的代理模式是基于类的代理,若想生成基于接口的代理,则需设置<aop:scoped-proxy>元素的proxy-target-classs属性为false。
<?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:aop="http://www.springframework.org/schema/aop" xmlns:c="http://www.springframework.org/schema/c" xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee" xsi:schemaLocation="http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd"> <bean id="cart" class="chapter3.practice4.ShoppingCart" scope="session"> <aop:scoped-proxy proxy-target-class="false" /> </bean> </beans>