Spring系列.Bean簡介


Bean屬性配置

Spring在讀取配置文件中bean的metadata后會構造一個個BeanDefination對象。后面Spring會根據這些BeanDefinition創建對象。在配置一個bean的時候我們可以配置下面這些元素:

元素 備注
class 設定類的全限定名
name 設置Bean的名稱,可以設置多個用逗號分隔
id/name Bean的唯一標識符,全局只能有一個
scope 設置Bean是單例還是原型,默認單例
constructor arguments 構造方法入參,進行依賴注入
properties 進行依賴注入
autowiring mode 自動注入模式
lazy-initialization mode 只對scope為單列的bean生效,設置為true會在getBean()時才創建bean實例
initialization method 設定Bean的初始化方法
destruction method 設定Bean的銷毀方法

除了通過配置信息來創建Bean,Spring還允許通過調用API的方式創建用戶在容器外部創建的對象。(通過DefaultListableBeanFactory類的registerSingleton方法和registerBeanDefinition方法)

In addition to bean definitions that contain information on how to create a specific bean, the ApplicationContextimplementations also permit the registration of existing objects that are created outside the container (by users). This is done by accessing the ApplicationContext’s BeanFactory through the getBeanFactory() method, which returns the BeanFactory DefaultListableBeanFactory implementation. DefaultListableBeanFactory supports this registration through the registerSingleton(..) and registerBeanDefinition(..) methods. However, typical applications work solely with beans defined through regular bean definition metadata.

雖然Spring容器還提供了registerSingleton(..)方法和registerBeanDefinition(..)來注冊單例Bean,但是不建議自己使用這個方法,因為我們可能在依賴注入之后再注冊了這個Bean。推薦使用配置BeanDefinition的方式來配置Bean。(其實這兩個方法更多是Spring框架自己使用,在配置文件以外的一些地方再注冊一些Bean到容器中)

關於上面表格中的id屬性和name屬性這邊多說一句。

id和name屬性都可以用來當做一個bean的標識符,他們兩個的區別是id只能給這個bean指定一個標識符,而name屬性可以同時給這個bean指定多個標識符(多個標識符之間用,隔開)。下面給出一個配置的列子

<!--經過下面的配置,bean1,bean2、name1、name2、alias1、alias2、alias3其實是一個Bean-->
<bean id="bean1,bean2" name="name1,name2" class="com.csx.demo.springdemo.service.MyBean1">
</bean>
<alias name="bean1,bean2" alias="alias1"/>
<alias name="name1" alias="alias2"/>
<alias name="name2" alias="alias3"/>

Bean命名

如果沒有給Bean指定一個標識符,Spring容器會默認給這個Bean設置一個標識符。用戶可以通過id和name兩個屬性來設置Bean的標識符,這些標識符需要在整個容器范圍內唯一,同時name可以指定多個用逗號分隔。

實例化Bean

實例化Bean一般有四種方式:默認構造函數、待參數的構造函數、靜態工廠類、實例方法創建Bean。需要我們注意的是Bean的實例化和依賴注入的區別。

  1. 默認構造函數方式
    <bean id="exampleBean" class="examples.ExampleBean"/>
  1. 帶參數的構造函數
    <bean id="Hello2" class="com.csx.personal.web.services.HelloImpl2">
        <constructor-arg index="0" value="xx"/>
        <constructor-arg index="1" value="xx"/>
        <constructor-arg index="2" ref="beanid"/>
    </bean>
  1. 使用靜態工廠類(不推薦使用)
    <bean id="bean3" class="cn.javass.spring.chapter2.HelloApiStaticFactory" factory-method="newInstance">
         <constructor-arg index="0" value="Hello Spring!"/>
    </bean>
    <!-- 使用examples.ClientService這個類的createInstance方法創建bean -->
    <bean id="clientService" class="examples.ClientService" factory-method="createInstance"/>

    public class ClientService {
        private static ClientService clientService = new ClientService();
        private ClientService() {}
        public static ClientService createInstance() {
        return clientService;
        }
    }
  1. 使用實例方法進行Bean創建
    <bean id="serviceLocator" class="examples.DefaultServiceLocator">
        <!-- inject any dependencies required by this locator bean -->
     </bean>
     <!-- 使用serviceLocator這個Bean的createClientServiceInstance方法創建Bean -->
     <bean id="clientService" factory-bean="serviceLocator" factory-method="createClientServiceInstance"/>
     <bean id="accountService" factory-bean="serviceLocator" factory-method="createAccountServiceInstance"/>
     //類定義	
     public class DefaultServiceLocator {
        private static ClientService clientService = new ClientServiceImpl();
        private static AccountService accountService = new AccountServiceImpl();
        public ClientService createClientServiceInstance() {
            return clientService;
        }
        public AccountService createAccountServiceInstance() {
            return accountService;
        }
      }

如果我們要通過xml的形式配置一個靜態內部類,可以參考下面的例子

For example, if you have a class called SomeThing in the com.example package, and this SomeThing class has a static nested class called OtherThing, the value of the class attribute on a bean definition would be com.example.SomeThing$OtherThing.

Bean的Scope

Spring默認支持的Scope

Scopes 描述
singleton 整個IOC容器中只有一個Bean
prototype 每次請求都會生成新的Bean
request 每個HTTP request都會生成一個新的Bean,只對web系列的ApplicationContext生效
session 每個session范圍內生成一個新的Bean,只對web系列的ApplicationContext生效
Application ServletContext范圍內生成一個新的Bean,只對web系列的ApplicationContext生效
websocket --

singleton類型的bean定義,在一個容器中只存在一個實例,所有對該類型bean的依賴都引用這一單一實例。

scope為prototype的bean,容器在接受到該類型的對象的請求的時候(調用getBean方法),會每次都重新 生成一個新的對象給請求方,雖然這種類型的對象的實例化以及屬性設置等工作都是由容器負責的,但是只要准備完畢,並且對象實例返回給請求方之后,容器就不 在擁有當前對象的引用,請求方需要自己負責當前對象后繼生命周期的管理工作,包括該對象的銷毀。也就是說,容器每次返回請求方該對象的一個新的實例之后, 就由這個對象“自生自滅”了。

單例Bean依賴原型Bean

當一個單例的Bean依賴一個原型Bean時,由於單例只初始化一次,所以拿到的原型Bean也只是我們第一次初始化時拿到的Bean,並不能達到我們想要的效果。此時我們可以使用Spring提供的look-up方式的注入來解決這個問題。

Request, Session, Application, and WebSocket Scopes

這三種Scope只對Web系列的ApplicationContext的生效。可以視同@RequestScope、@SessionScope和@ApplicationScope使之生效。

自定義Scope

Spring還支持自定義scope,需要時可以學些下這個特性。

Bean的擴展點(注意和容器擴展點的區別)

Spring提供了一系列接口讓用戶來自定義Bean的屬性(注意和容器擴展點那一個章節的區別),主要的接口有:

  • Lifecycle Callbacks;
  • ApplicationContextAware and BeanNameAware;
  • Other Aware Interfaces;

生命周期回調

所謂生命周期交互就是指在容器創建Bean和銷毀Bean之前做某些操作。在Spring中我們可以通過讓Bean實現InitializingBean和DisposableBean接口,使用@PostConstruct和@PreDestroy以及通過如下的配置實現。

    <bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/> 
    <bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>

如果我們給一個Bean同時配置了上面多種的初始化和銷毀機制,那么他們的執行順序如下:

初始化順序

  1. Methods annotated with @PostConstruct (這個方法在構造函數之后執行,是最佳實踐,可以和Spring API解耦)
  2. afterPropertiesSet() as defined by the InitializingBean callback interface(不建議使用,會耦合Spring API)
  3. A custom configured init() method(普通的xml配置文件中配置的初始化方法)
    析構順序
  4. Methods annotated with @PreDestroy(建議使用)
  5. destroy() as defined by the DisposableBean callback interface (不建議使用)
  6. A custom configured destroy() method (普通的xml文件中配置的銷毀方法)

Spring完整的初始化順序

  1. 容器啟動,實例化所有實現了BeanFactoyPostProcessor接口的類;這步會在任何普通Bean實例化之前加載;
  2. 實例化剩下的單例Bean,對這些Bean進行依賴注入;
  3. 如果Bean有實現BeanNameAware的接口那么對這些Bean進行調用;
  4. 如果Bean有實現BeanFactoryAware接口的那么對這些Bean進行調用;
  5. 如果Bean有實現ApplicationContextAware接口的那么對這些Bean進行調用;
  6. 如果配置有實現BeanPostProcessor的Bean,那么調用它的postProcessBeforeInitialization方法;
  7. 調用@PostConstruct注解的方法;
  8. 如果Bean有實現InitializingBean接口那么對這些Bean進行調用;
  9. 如果Bean配置有init屬性,那么調用它屬性中設置的方法;
  10. 如果配置有實現BeanPostProcessor的Bean,那么調用它的postProcessAfterInitialization方法;
  11. Bean正常的使用;
  12. 調用@PreDestroy標注的方法;
  13. 調用DisposableBean接口的destory方法;
  14. 調用Bean定義是指定的destroy-method方法;

LifeCycle和SmartLifeCycle接口

Spring提供了LifeCycle接口,實現了這個接口的Bean在Spring容器調用start()和stop()方法的時候能收到Spring的回調信息,分別調用這個Bean的start()和stop()方法。

Aware接口

Spring提供了很多aware接口讓Bean來實現,提示IOC容器,這個Bean需要得到容器的某些組件或元素。

  • ApplicationContextAware
  • ApplicationEventPublisherAEwvaenrte
  • BeanClassLoaderAware
  • BeanFactoryAware
  • BeanNameAware
  • BootstrapContextAware:Typically available only in JCA aware ApplicationContext instances.
  • LoadTimeWeaverAware
  • MessageSourceAware
  • NotificationPublisherAwareSpring:Spring JMX notification publisher.
  • ResourceLoaderAware
  • ServletConfigAware
  • ServletContextAware


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM