Bean Scopes,Spring Bean的作用域,也就是Spring创立的Bean实例的失效范畴。

Spring提供了如下6中不同的作用域:

  1. singleton: 单例Bean,每一个Spring IoC容器中只有一个Bean实例,这是Bean的默认作用域。
  2. prototype:原型Bean,每申请一次就生成一个新的Bean实例
  3. request:仅对 web-aware Spring ApplicationContext失效,每一次HTTP申请生成一个Bean实例。
  4. session: 仅对 web-aware Spring ApplicationContext失效,每一个HTTP session对应一个Bean 实例。
  5. application: 仅对 web-aware Spring ApplicationContext失效,ServletContext生命周期对应一个Bean实例。
  6. websocket:仅对 web-aware Spring ApplicationContext失效,websocket申请对应一个Bean实例。

其中有4个是和web-aware Spring ApplicationContext相干的,也就是和web利用相干,最罕用的是singleton和prototype两种。

单例Bean

singleton,单例Bean,是Spring默认的Bean作用域,咱们在配置Bean的时候如果没有指定作用域,那么他的作用域就是singleton。

Spring官网的一张图高深莫测的讲清楚了单例Bean的含意:

定义了一个id为accountDao的Bean,被其余3个Bean援用。如图,咱们在定义accountDao的时候没有指定作用域,默认的,他的作用域就是singleton,单例Bean。那么,在整个Spring IoC容器中就只创立一个accountDao的Bean实例,3个援用类援用的其实是同一个accountDao实例。

这种状况系按咱们肯定要留神accountDao的线程平安问题!应用单例Bean的时候你肯定要留神线程平安问题,尽可能的防止在单例Bean中应用属性对象,或者你十分明确的晓得该属性不须要关注线程安全性!

接下来思考一个问题:定义为单例Bena就肯定示意整个Spring IoC容器中只有该类的一个对象吗?

答案显示是No,你当然能够在Spring IoC容器中为某一个类创立多个单例对象。

原型Bean

原型Bean指的是Spring IoC容器中会有多个Bena实例,利用没申请一次,Spring IoC容器就会生成一个新的Bean实例返回。

如图,accountDao定义为原型Bean,被其余3个Bean援用,不论其余3个Bean是单例还是原型Bean,Spring IoC注入的accountDao都会是3个不同的对象。

原型Bean在申明的时候须要显式指定scope:

 <bean id="dependencyB" class="springTest.DependencyB" scope="prototype">    </bean>

也通过注解形式指定scope:

@Component@Scope("prototype")public class DependencyB implements IDependencyB{    @Autowired    //@Qualifier(value="dependencyA3")    private IDependencyA dependencyA;    public static void main(String[] args) {        System.out.println("I am a new comer...hello world ");    }    @Override    public void testB(){        System.out.print("This is DependencyB's test and ...");        dependencyA.test();    }

启动类加测试代码:

public class App {    public static void main(String[] args) {        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfiguration.class);        System.out.println("Now start to getbean...");        DependencyB dependencyB = applicationContext.getBean(DependencyB.class);        dependencyB.testB();        System.out.println(dependencyB);        dependencyB=applicationContext.getBean(DependencyB.class);        System.out.println(dependencyB);    }}

执行启动类:

Now start to getbean...This is DependencyB's test and ...I am DependencyA test...springTest.DependencyB@53ca01a2springTest.DependencyB@358c99f5

能够看到两次获取DependencyB,失去的是不同的对象。

原型Bean的非凡之处还在于:创立的时候交给了Spring IoC,然而Spring IoC并不负责销毁。然而好消息是,因为原型Bean的特殊性,所以,Spring IoC容器也没有必要在每次创立之后缓存该实例,Spring IoC容器只须要new出一个对象(其实不是New的,是通过反射机制或者CGLIB创立的)间接返回给利用就OK,所以,也就不会导致内存透露,

单例Bena和原型Bean的依赖

如果一个原型Bean要依赖一个单例Bena,其实是没有任何问题的,因为依赖注入是产生在Bean实例化之后的属性赋值阶段,原型Bean在每次申请的时候都会进行一次属性赋值、都会执行一次依赖注入,单例Bean depencyA会注入到原型Bean dependencyB中,不会存在任何问题。

其实咱们下面的例子,原型Bean dependencyB就是依赖单例Bean dependencyA的,咱们把DependencyB的test办法稍加革新、打印一下依赖对象dependencyA:

    @Override    public void testB(){        System.out.print("This is DependencyB's test and ..."+dependencyA);        dependencyA.test();    }

执行启动类:

Now start to getbean...This is DependencyB's test and ...springTest.DependencyA@53ca01a2I am DependencyA test...springTest.DependencyB@358c99f5This is DependencyB's test and ...springTest.DependencyA@53ca01a2I am DependencyA test...springTest.DependencyB@3ee0fea4

咱们会发现两次获取到的尽管是不同的dependencyB对象,然而他们的依赖对象dependencyA却是雷同的对象,因为dependencyA是单例Bean。

然而反过来就不是这么回事了:如果一个单例Bean依赖一个原型Bean会怎么样?

为此,咱们把上例中的DependencyB批改为单例Bean,把DependencyA批改为原型Bean,做一下测试。

只须要把@Scope("prototype")注解从DependencyB类转移到DependencyA上即可。

运行启动类:

 Now start to getbean...This is DependencyB's test and ...springTest.DependencyA@53ca01a2I am DependencyA test...springTest.DependencyB@358c99f5This is DependencyB's test and ...springTest.DependencyA@53ca01a2I am DependencyA test...springTest.DependencyB@358c99f5

咱们发现尽管定义DependencyA为原型Bean,然而两次获取到的DependencyB的依赖对象DependencyA是同一个对象。

这也不难理解,Bena的注入是在Bean实例化之后的属性赋值阶段解决的,单例Bean只实例化一次、属性负责也只产生一次,所以,依赖对象也只能被注入一次,尽管属性是原型Bean,因为只能被注入一次所以也就只能是同一个对象了。

其实倡议最好不要在单例Bean中援用原型Bean,如果非要这么做的话,Spring也提供了一种解决办法:Method Injection,能够采纳xml配置或注解@Lookup实现,个人感觉利用很少,临时疏忽。

上一篇 Spring FrameWork从入门到NB - 主动拆卸