Spring
在讀取配置文件中bean的metadata後會構造一個個BeanDefination對象。後面Spring會根據這些BeanDefinition建立對象。在配置一個bean的時候咱們能夠配置下面這些元素:java
元素 | 備註 |
---|---|
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還容許經過接口的方式建立用戶在容器外部建立的對象。(經過DefaultListableBeanFactory類的registerSingleton方法和registerBeanDefinition方法)web
In addition to bean definitions that contain information on how to create a specific bean, the
ApplicationContext
implementations 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 thegetBeanFactory()
method, which returns the BeanFactoryDefaultListableBeanFactory
implementation.DefaultListableBeanFactory
supports this registration through theregisterSingleton(..)
andregisterBeanDefinition(..)
methods. However, typical applications work solely with beans defined through regular bean definition metadata.spring
雖然Spring容器還提供了registerSingleton(..)方法和registerBeanDefinition(..)來註冊單例Bean,可是不建議本身使用這個方法,由於咱們可能在依賴注入以後再註冊了這個Bean。推薦使用配置BeanDefinition的方式來配置Bean。(其實這兩個方法更可能是Spring框架本身使用,在配置文件之外的一些地方再註冊一些Bean到容器中)websocket
關於上面表格中的id屬性和name屬性這邊多說一句。session
id和name屬性均可以用來當作一個bean的標識符,他們兩個的區別是id只能給這個bean指定一個標識符,而name屬性能夠同時給這個bean指定多個標識符(多個標識符之間用,隔開)。下面給出一個配置的列子app
<!--通過下面的配置,bean1,bean二、name一、name二、alias一、alias二、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指定一個標識符,Spring容器會默認給這個Bean設置一個標識符。用戶能夠經過id和name兩個屬性來設置Bean的標識符,這些標識符須要在整個容器範圍內惟一,同時name能夠指定多個用逗號分隔。框架
實例化Bean通常有四種方式:默認構造函數、待參數的構造函數、靜態工廠類、實例方法建立Bean。須要咱們注意的是Bean的實例化和依賴注入的區別。socket
<bean id="exampleBean" class="examples.ExampleBean"/>
<bean id="Hello2" class="com.csx.personal.web.services.HelloImpl2"> <constructor-arg index="0" value="chensongxia"/> <constructor-arg index="1" value="zhaoru"/> <constructor-arg index="2" ref="beanid"/> </bean>
<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; } }
<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的形式配置一個靜態內部類,能夠參考下面的例子ide
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.函數
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,並不能達到咱們想要的效果。此時咱們可使用Spring提供的look-up方式的注入來解決這個問題。
這三種Scope只對Web系列的ApplicationContext的生效。能夠視同@RequestScope、@SessionScope和@ApplicationScope使之生效。
Spring還支持自定義scope,須要時能夠學些下這個特性。
Spring提供了一系列接口讓用戶來自定義Bean的屬性(注意和容器擴展點那一個章節的區別),主要的接口有:
所謂生命週期交互就是指在容器建立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同時配置了上面多種的初始化和銷燬機制,那麼他們的執行順序以下:
初始化順序
Spring完整的初始化順序
- 容器啓動,實例化全部實現了BeanFactoyPostProcessor接口的類;這步會在任何普通Bean實例化以前加載;
- 實例化剩下的單例Bean,對這些Bean進行依賴注入;
- 若是Bean有實現BeanNameAware的接口那麼對這些Bean進行調用;
- 若是Bean有實現BeanFactoryAware接口的那麼對這些Bean進行調用;
- 若是Bean有實現ApplicationContextAware接口的那麼對這些Bean進行調用;
- 若是配置有實現BeanPostProcessor的Bean,那麼調用它的postProcessBeforeInitialization方法;
- 調用@PostConstruct註解的方法;
- 若是Bean有實現InitializingBean接口那麼對這些Bean進行調用;
- 若是Bean配置有init屬性,那麼調用它屬性中設置的方法;
- 若是配置有實現BeanPostProcessor的Bean,那麼調用它的postProcessAfterInitialization方法;
- Bean正常的使用;
- 調用@PreDestroy標註的方法;
- 調用DisposableBean接口的destory方法;
- 調用Bean定義是指定的destroy-method方法;
Spring提供了LifeCycle接口,實現了這個接口的Bean在Spring容器調用start()和stop()方法的時候能收到Spring的回調信息,分別調用這個Bean的start()和stop()方法。
Spring提供了不少aware接口讓Bean來實現,提示IOC容器,這個Bean須要獲得容器的某些組件或元素。