2018/1/1

摘抄:

     对于使用Spring框架的开发人员来说,我们主要做的主要有两件事情:①开发Bean;②配置Bean;而Spring帮我们做的就是根据配置文件来创建Bean实例,并调用Bean实例的方法来完成“依赖注入”,可以把Spring容器理解成一个大型工厂,Bean就是该工厂的产品,工厂(Spirng容器)里能生产出来什么样的产品(Bean),完全取决于我们在配置文件中的配置。


Bean的作用域:

     When you create a bean definition what you are actually creating is a recipe for creating actual instances of the class defined by that bean definition. The idea that a bean definition is a recipe is important, because it means that, just like a class, you can potentially have many object instances created from a single recipe.

大意:

,这个限定是bean的一个实例。bean的限定是很重要的,因为它意味着,我们可能有许多对象实例是从一个限定的bean中创建的。


    You can control not only the various dependencies and configuration values that are to be plugged into an object that is created from a particular bean definition, but also the scope of the objects created from a particular bean definition. This approach is very powerful and gives you the flexibility to choosethe scope of the objects you create through configuration instead of having to 'bake in' the scope of an object at the Java class level. Beans can be defined to be deployed in one of a number of scopes: out of the box, the Spring Framework supports exactly five scopes (of which three are available only if you are using a web-aware ​​ApplicationContext​​).

大意:

    我们不仅能控制特定bean定义中创建的对象插入的各种依赖项和配置值,还可以控制从特定bean定义创建的对象的范围(即IOC)。这种方法是非常强大的,从而我们可以通过配置,灵活地创建和选择范围的对象;而不是在 java类层次的对象范围里,进行死板的定义。bean作用域可以定义为多个:开箱,Spring框架支持的五个(如果使用的是 ApplicationContext,则只有3个可选)。



The scopes supported out of the box are listed below:

Spring(18):理解Bean的作用域 与 生命周期_生命周期

图1(官方)


Spring(18):理解Bean的作用域 与 生命周期_spring_02

图2(译文)


The singleton scope:

     When a bean is a singleton, only one shared instance of the bean will be managed, and all requests for beans with an id or ids matching that bean definition will result in that one specific bean instance being returned by the Spring container.

    To put it another way, when you define a bean definition and it is scoped as a singleton, then the Spring IoC container will create exactly one instance of the object defined by that bean definition. This single instance will be stored in a cache of such singleton beans, and all subsequent requests and references for that named bean will result in the cached object being returned.


大意:单例模式,在整个Spring IoC容器中,使用singleton定义的Bean将只有一个实例。无论实现多少个对象,实际使用同一个实例。

Spring(18):理解Bean的作用域 与 生命周期_作用域_03

图3(singleton)

eg:


<!-- using spring-beans-2.0.dtd -->
<bean id="accountService" class="com.foo.DefaultAccountService" scope="prototype"/>

<!-- the following is equivalent and preserved for backward compatibility in spring-beans.dtd -->
<bean id="accountService" class="com.foo.DefaultAccountService" singleton="false"/>


The prototype scope:


     The non-singleton, prototype scope of bean deployment results in the creation of a new bean instance every time a request for that specific bean is made (that is, it is injected into another bean or it is requested via a programmatic getBean() method call on the container). As a rule of thumb, you should use the prototype scope for all beans that are stateful, while the singleton scope should be used for stateless beans.

    The following diagram illustrates the Spring prototype scope. Please note that a DAO would not typically be configured as a prototype, since a typical DAO would not hold any conversational state; it was just easier for this author to reuse the core of the singleton diagram.



大意:原型模式,每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例。

Spring(18):理解Bean的作用域 与 生命周期_生命周期_04

图4(prototype )


eg:


<!-- using spring-beans-2.0.dtd -->
<bean id="accountService" class="com.foo.DefaultAccountService" scope="prototype"/>

<!-- the following is equivalent and preserved for backward compatibility in spring-beans.dtd -->
<bean id="accountService" class="com.foo.DefaultAccountService" singleton="false"/>




      比较常用的是singleton 和 prototype 两种作用域,对于singleton作用域,每次请求该Bean都将获得相同的实例,Spring容器负责跟踪监视Bean实例的状态,负责维护Bean实例的生命周期行为,如果一个Bean被设置成prototype作用域,程序每次请求该id的Bean,Spring都会创建一个新的Bean实例,然后返回给程序,在这种情况下,Spring容器仅仅使用new 关键字创建Bean实例,一旦创建成功,容器Spring不再对Bean的生命周期负责,也不会维护Bean实例的状态。

      如果不指定Bean的作用域,Spring默认使用singleton作用域。Java在常见Java实例时,需要进行内存申请,销毁实例是,需要完成垃圾回收,这些工作都会导致系统开销的增加。因此prototype作用域Bean 的创建销毁代价比较大。而singleton作用域的Bean 实例一旦创建成功,可以重复使用,因此,除非必要,否则避免将Bean作用域设置成prototype。


The other scopes:

     namely request, session, and global session are for use only in web-based applications (and can be used irrespective of which particular web application framework you are using, if indeed any). In the interest of keeping related concepts together in one place in the reference documentation, these scopes are described here.

     The scopes that are described in the following paragraphs are only available if you are using a web-aware Spring ApplicationContext implementation (such as XmlWebApplicationContext). If you try using these next scopes with regular Spring IoC containers such as the XmlBeanFactory or ClassPathXmlApplicationContext, you will get an IllegalStateException complaining about an unknown bean scope.


The request scope:


    With the above bean definition in place, the Spring container will create a brand new instance of the LoginAction bean using the 'loginAction' bean definition for each and every HTTP request. That is, the 'loginAction' bean will be effectively scoped at the HTTP request level. You can change or dirty the internal state of the instance that is created as much as you want, safe in the knowledge that other requests that are also using instances created off the back of the same 'loginAction' bean definition will not be seeing these changes in state since they are particular to an individual request. When the request is finished processing, the bean that is scoped to the request will be discarded.



大意:对于每次HTTP请求,使用request定义的Bean都将产生一个新的实例,每次HTTP请求都将产生不同的Bean实例,该作用域仅在给予web的Spring ApplicationContext情形下有效。


eg:


<bean id="loginAction" class="com.foo.LoginAction" scope="request"/>




The session scope:


    With the above bean definition in place, the Spring container will create a brand new instance of the UserPreferences bean using the 'userPreferences' bean definition for the lifetime of a single HTTP Session. In other words, the 'userPreferences' bean will be effectively scoped at the HTTP Session level. Just like request-scoped beans, you can change the internal state of the instance that is created as much as you want, safe in the knowledge that other HTTP Session instances that are also using instances created off the back of the same 'userPreferences' bean definition will not be seeing these changes in state since they are particular to an individual HTTP Session. When the HTTP Session is eventually discarded, the bean that is scoped to that particular HTTP Session will also be discarded.

大意:对于每次HTTP Session ,使用session定义的Bean都将产生一个新实例,该作用域仅在给予web的Spring ApplicationContext情形下有效。


eg:

<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>



The global session scope:

    The global session scope is similar to the standard HTTP Session scope (described immediately above), and really only makes sense in the context of portlet-based web applications. The portlet specification defines the notion of a global Session that is shared amongst all of the various portlets that make up a single portlet web application. Beans defined at the global session scope are scoped (or bound) to the lifetime of the global portlet Session.
    Please note that if you are writing a standard Servlet-based web application and you define one or more beans as having global session scope, the standard HTTP Session scope will be used, and no error will be raised.

大意:每个全局得HTTP Session对应一个Bean实例,该作用域仅在给予web的Spring ApplicationContext情形下有效。


eg:

<bean id="userPreferences" class="com.foo.UserPreferences" scope="globalSession"/>




Bean生命周期:

       Spring Bean的完整生命周期从创建Spring容器开始,直到最终Spring容器销毁Bean,这其中包含了一系列关键点。

Spring(18):理解Bean的作用域 与 生命周期_作用域_05

图5


Spring(18):理解Bean的作用域 与 生命周期_作用域_06

图6


各种接口方法分类:



Bean的完整生命周期经历了各种方法调用,这些方法可以划分为以下几类:


1、Bean自身的方法:这个包括了Bean本身调用的方法和通过配置文件中<bean>的init-method和destroy-method指定的方法;


2、Bean级生命周期接口方法:这个包括了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这些接口的方法;


3、容器级生命周期接口方法:这个包括了InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为“后处理器”;


4、工厂后处理器接口方法:这个包括了AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer 等等非常有用的工厂后处理器接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。