Spring5 Bean的作用域

Posted 冰点IT

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring5 Bean的作用域相关的知识,希望对你有一定的参考价值。

1、什么是Bean的作用域

   Bean的作用域也就是Bean的作用范围,Spring默认Bean的作用域是单例(Singletion),也就是说Bean在容器加载时只会被实例化一次,之后无论被注入多少次,都使用的是同一个实例。那么Spring还未我们提供了那些作用域呢?

      单例(Singleton):在整个应用中,只创建一个Bean的实例。

      原型(Prototype):每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的Bean实例。

      会话(Session):在Web应用中,Spring会为每一个回话创建一个bean的实例。

      请求(Request):在Web应用中,Spring会为每一个请求创建一个Bean的实例。

     应用(Application):在Web应用中,Spring会为每一个Servlet上下文创建一个Bean的实例。

      WebSocket:Spring会为每个webSocket的生命周期创建一个Bean的实例。

2、作用域的使用

2.1、原型作用域的使用

基于JavaConfig:

//简单Java类public class BeanPrototypeScope {}//BeanPrototypeScope被注入public class UseProtoBean { private BeanPrototypeScope beanPrototypeScope; public UseProtoBean(BeanPrototypeScope beanPrototypeScope) { this.beanPrototypeScope = beanPrototypeScope; }}//JavaConfig配置@Configurationpublic class BeanConfig { public static Logger logger = LoggerFactory.getLogger(BeanConfig.class); //定义BeanPrototypeScope为一个Bean,所用域为原型 @Bean@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) public BeanPrototypeScope beanPrototypeScope() { return new BeanPrototypeScope(); } //定义UseProtoBean 为一个Bean,并注入BeanPrototypeScope的实例 @Bean public UseProtoBean useProtoBean(BeanPrototypeScope beanPrototypeScope) { logger.info("注入时BeanPrototypeScope的实例是:{}",beanPrototypeScope.toString()); return new UseProtoBean(beanPrototypeScope); }}

测试类:

public class TestBeanScope { public static Logger logger = LoggerFactory.getLogger(TestBeanScope.class);public static AnnotationConfigApplicationContext acac = new AnnotationConfigApplicationContext(BeanConfig.class); @Test public void testPrototype() { BeanPrototypeScope beanPrototypeScope = acac.getBean("beanPrototypeScope", BeanPrototypeScope.class); logger.info("通过上下文获取时BeanPrototypeScope的实例是:{}",beanPrototypeScope.toString()); }}

      有原型作用域的特性可知,BeanPrototypeScope会在通过容器获取的时候实例化一次,然后在注入到UseProtoBean时再实例化一次,下面来看运行结果。

运行结果:

21:51:51,372 INFO main configuration.BeanConfig:30 - 注入时BeanPrototypeScope的实例是:com.icypt.learn.BeanPrototypeScope@4c5ae43b21:51:51,413 INFO main learn.TestBeanScope:23 - 通过上下文获取时BeanPrototypeScope的实例是:com.icypt.learn.BeanPrototypeScope@6f3187b0

      由运行结果可知,两次产生的实例确实各不相同。

基于XmlConfig使用:

<bean id="beanPrototypeScope" class="com.icypt.learn.BeanPrototypeScope" scope="prototype"/>

2.2、会话和请求作用域的使用

      在Web应用中,如果能够实例化在会话和请求范围内共享的bean,那将是非常有价值的事情。例如,在某个网上商城应用中,我们肯定希望购物车这个Bean是在会话范围内共享的。假如它是一个单例的Bean且不做任何的硬编码,那岂不是每个用户都向同一个购物车添加商品了,假如它是一个原型的Bean,那么用户添加的商品,可能在其他地方就不可用了,那么就购物车这个Bean来说,把它定义为一个会话作用域的Bean是最合适不过的了。

基于JavacConfig使用

@Bean@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.INTERFACES)public ShoppingCar shoppingCar() { return new ShoppingCar();}

      定义会话作用域的方式和原型作用域是一致的,都是使用@Scope,但唯一不同的地方是,在定义会话作用域时我们指定了代理模式。

      proxyMode = ScopedProxyMode.INTERFACES,这段代码表示ShoppingCar需要被代理,且这个代理要实现ShoppingCar的接口,并委托给它的实现类。那么为什么要定义这个代理规则呢?先看一段代码:

@Beanpublic User user(ShoppingCar shoppingCar) { return new User(shoppingCar);}

      代码中User是一个单例的Bean,但是依赖了ShoppingCar这个会话作用域的Bean,那么当Spring加载容器的时候,由于此时ShoppingCar还不会被实例,但是Spring又要建立其引用关系,由于每个User对应的ShoppingCar是不同的,此时Spring容器又无法判断要使用哪一个ShoppingCar,所以Spring只能将ShoppingCar的代理注入到User这个bean之中,对外暴露和ShoppingCar相同的方法,当User调用ShoppingCar的方法时,代理会对其进行懒加载解析并将调用委托给会话作用域内的ShoppingCar的实例来完成, 那么假如ShoppingCar就是一个具体的类并没有实现购物车的标准接口,此时的代理模式又改如何调整呢?

@Bean@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)public ShoppingCar shoppingCar() { return new ShoppingCar();}

      如果ShoppingCar就是一个具体的类,则必须使用CGLIB来生成基于类的代理。

基于XmlConfig使用:

<bean id="shoppingCar" class="com.icypt.learn.ShoppingCar"> <!-- 默认是基于CGLIB代理的,也就是基于类的代理--> <aop:scoped-proxy/></bean>

当然我们也可以设置为基于接口的代理:

<bean id="shoppingCar" class="com.icypt.learn.ShoppingCar"> <aop:scoped-proxy proxy-target-class="false"/></bean>

那么以上就是Bean作用域的全部内容了,application、websocket、request等作用域的使用方式和session的使用方式相同,都是需要创建代理的这里就不一一介绍了,下次我们讨论Spring的EL表达式。

关注我

冰点IT,探索最新开发技术,记录追求梦想的点点滴滴!


    长按二维码,或点击最上方蓝色的 冰点IT 关注我,您的关注是对我最好的鼓励!




以上是关于Spring5 Bean的作用域的主要内容,如果未能解决你的问题,请参考以下文章

[Spring5]IOC容器_Bean管理_bean的作用域和bean的生命周期

Java Spring5之IOC容器

Spring5学习笔记 — “IOC操作Bean管理(基于注解)”

Spring5学习笔记 — “IOC操作Bean管理(基于注解)”

[Spring5]IOC容器_Bean管理注解方式_创建对象

Spring5 Java代码装配Bean