javascript
Spring--IoC(1)
目錄
?
IoC容器和Bean
Container
配置元數(shù)據(jù)
Container實(shí)例化
使用Container
Bean
Bean命名
Bean實(shí)例化
構(gòu)造函數(shù)實(shí)例化
靜態(tài)工廠方法實(shí)例化
實(shí)例工廠方法實(shí)例化
依賴
依賴注入
構(gòu)造函數(shù)注入
setter注入
依賴處理過程
配置詳解
直接賦值
引用其他bean
內(nèi)部Bean
集合
Null及空字符串值
XML短命名空間
復(fù)合屬性名稱
depends-on
延遲加載bean
自動(dòng)裝配
自動(dòng)裝配的限制與缺點(diǎn)
裝配時(shí)排除bean
方法注入
Lookup Method
replace-method注入
Bean Scope
Request, Session, Application, WebSocket Scopes
初始化Web Configuration
Request scope
Session Scope
Application Scope
自定義Scope
自定義Bean生命周期
Lifecycle Callbacks
初始化回調(diào)
銷毀回調(diào)
默認(rèn)初始化回調(diào)與銷毀回調(diào)
組合生命周期機(jī)制
開啟和關(guān)閉回調(diào)
在非Web應(yīng)用環(huán)境中優(yōu)雅地關(guān)閉Spring Ioc窯器
ApplicationContextAware和BeanNameAware
Other Aware Interfaces
Bean定義繼承
IoC容器和Bean
Spring的核心思想是控制反轉(zhuǎn)(IoC),也被稱為依賴注入。它是一個(gè)過程,對(duì)象僅通過構(gòu)造函數(shù)參數(shù)、工廠方法的參數(shù)
或把從工廠方法構(gòu)造或返回的對(duì)象實(shí)例設(shè)置為屬性等方式定義他們的依賴(一起工作的對(duì)象)。然后,容器在bean被創(chuàng)建后注入這些依賴項(xiàng)。這個(gè)過程基本上是bean自身通過直接構(gòu)造類或服務(wù)定位器模式等機(jī)制來控制其依賴項(xiàng)的實(shí)例化或位置的反過程(因此稱為控制反轉(zhuǎn))。
核心包:org.springframework.beans 和 org.springframework.context。BeanFactory接口提供了一種高級(jí)配置機(jī)制,能夠管理任何類型的對(duì)象。applicationContext是BeanFactory的子接口。它補(bǔ)充了:
- 更容易與Spring的AOP功能集成
- 消息資源處理(用于國際化)
- 事件發(fā)布
- 應(yīng)用層特定的上下文,如用于Web應(yīng)用程序的WebApplicationContext。
BeanFactory提供了配置框架和基本功能,ApplicationContext添加了更多特定于企業(yè)的功能。
在Spring中,構(gòu)成應(yīng)用程序主干并由SpringIOC容器管理的對(duì)象稱為bean。bean是一個(gè)由SpringIOC容器實(shí)例化、組裝和管理的對(duì)象。否則,bean只是應(yīng)用程序中許多對(duì)象之一。bean以及它們之間的依賴關(guān)系反映在容器使用的配置元數(shù)據(jù)中。
Container
org.springframework.context.applicationContext接口表示SpringIOC容器,負(fù)責(zé)實(shí)例化、配置和組裝bean。容器通過讀取配置元數(shù)據(jù)獲取關(guān)于要實(shí)例化、配置和組裝的對(duì)象的指令。配置元數(shù)據(jù)以XML、Java注解或Java代碼來表示。
Spring提供了applicationContext接口的幾個(gè)實(shí)現(xiàn)。在獨(dú)立應(yīng)用程序中,通常創(chuàng)建ClassPathXMLApplicationContext或FileSystemXMLApplicationContext的實(shí)例。雖然XML是定義配置元數(shù)據(jù)的傳統(tǒng)格式,但您可以通過提供少量XML配置來指示容器使用Java注解或代碼作為元數(shù)據(jù)格式,以聲明性地支持對(duì)這些附加元數(shù)據(jù)格式的支持。
Spring工作原理:
配置元數(shù)據(jù)
配置元數(shù)據(jù)表示作為應(yīng)用程序開發(fā)人員,如何通知Spring容器實(shí)例化、配置和組裝應(yīng)用程序中的對(duì)象。配置方式包括:
- XML配置
- 基于注解的配置:Spring2.5引入了對(duì)基于注解的配置元數(shù)據(jù)的支持。
- 基于Java的配置:從Spring 3開始,Spring JavaConFig項(xiàng)目提供的許多特性成為核心Spring框架的一部分。因此,可以使用Java而不是XML文件來定義應(yīng)用程序類外部的bean。要使用這些新功能,請(qǐng)參見@configuration、@bean、@import和@dependson注釋。
Spring配置由容器必須管理的至少一個(gè)且通常不止一個(gè)bean定義組成。基于XML的配置元數(shù)據(jù)將這些bean配置為頂級(jí)<beans/>元素中的<bean/>元素。Java配置通常在被@Configuration注解的類中使用@bean注解的方法。
<?xml version="1.0" encoding="UTF-8"?>
<beans? ......>
??? <bean id="..." class="...">? ?
??????? <!-- collaborators and configuration for this bean go here -->
??? </bean>
</beans>
?
id屬性是標(biāo)識(shí)單個(gè)bean定義的字符串。
class屬性定義bean的類型并使用完全限定的類名。
Container實(shí)例化
Spring IoC 容器需要在應(yīng)用啟動(dòng)時(shí)進(jìn)行實(shí)例化。在實(shí)例化過程中,IoC 容器會(huì)從各種外部資源(如本地文件系統(tǒng)、Java 類路徑等)加載配置元數(shù)據(jù),提供給ApplicationContext構(gòu)造函數(shù)。
?
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
組合配置元數(shù)據(jù)
當(dāng)系統(tǒng)規(guī)模比較大時(shí)\通常會(huì)讓bean定義分到多個(gè)XML文件。
<beans>
??? <import resource="services.xml"/>
??? <import resource="resources/messageSource.xml"/>
??? <import resource="/resources/themeSource.xml"/>
??? <bean id="bean1" class="..."/>
??? <bean id="bean2" class="..."/>
</beans>
外部bean定義是從三個(gè)文件加載的:services.xml、messagesource.xml和themesource.xml。所有位置路徑都是執(zhí)行導(dǎo)入的定義文件的相對(duì)路徑,因此services.xml必須與執(zhí)行導(dǎo)入的文件位于同一目錄或類路徑位置,而messagesource.xml和themesource.xml必須位于導(dǎo)入文件位置下方的資源位置。前導(dǎo)斜杠被忽略
可以(但不推薦)使用相對(duì)的“..”路徑引用父目錄中的文件。這樣做會(huì)創(chuàng)建對(duì)當(dāng)前應(yīng)用程序外部文件的依賴關(guān)系。特別是,對(duì)于classpath:urls(例如classpath:../services.xml),不建議使用此引用,運(yùn)行時(shí)解析過程將選擇“最近”的classpath根目錄,然后查看其父目錄。類路徑配置更改可能導(dǎo)致選擇其他不正確的目錄。
始終可以使用完全限定的資源位置,而不是相對(duì)路徑:例如,文件:c:/config/services.xml或classpath:/config/services.xml。但是,請(qǐng)注意,您正在將應(yīng)用程序的配置耦合到特定的絕對(duì)位置。通常情況下,最好通過在運(yùn)行時(shí)根據(jù)JVM系統(tǒng)屬性解析的“$…”占位符,為此類絕對(duì)位置保留間接尋址。
命名空間本身提供了導(dǎo)入指令功能。在Spring-提供的一系列XML名稱空間中,除了純bean定義之外,還提供了其他配置功能,例如Context和Util名稱空間。
使用Container
ApplicationContext 是高級(jí)工廠的接口,能維護(hù)不同bean及其依賴項(xiàng)的注冊(cè)表。其提供的方法T getBean(String name, Class<T> requiredType),可以用于檢索bean的實(shí)例。
// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
// retrieve configured instance
PetStoreService service = context.getBean("petStore", PetStoreService.class);
// use configured instance
List<String> userList = service.getUsernameList();
Bean
Spring Container管理多個(gè)Bean,在Container內(nèi)部,Bean是通過BeanDefinition表現(xiàn)的。包含下列元數(shù)據(jù):
- 包限定類名。通常是正在定義的bean的實(shí)際實(shí)現(xiàn)類。
- bean行為配置元素。用于說明bean在容器中的行為(范圍、生命周期回調(diào)等)。
- 對(duì)bean執(zhí)行其工作所需的其他bean的引用。這些引用也稱為合作者或依賴關(guān)系。
- 要為新創(chuàng)建的對(duì)象設(shè)置的其他配置,例如,池的大小限制或管理連接池的bean中要使用的連接數(shù)。
元數(shù)據(jù)轉(zhuǎn)換為組成每個(gè)bean定義的一組屬性
| Property | Explained in…? |
| Class | Instantiating Beans |
| Name | Naming Beans |
| Scope | Bean Scopes |
| Constructor arguments | Dependency Injection |
| Properties | Dependency Injection |
| Autowiring mode | Autowiring Collaborators |
| Lazy initialization mode | Lazy-initialized Beans |
| Initialization method | Initialization Callbacks |
| Destruction method | Destruction Callbacks |
除了包含有關(guān)如何創(chuàng)建特定bean的信息的bean定義之外,applicationContext實(shí)現(xiàn)還允許注冊(cè)容器外部(由用戶)創(chuàng)建的現(xiàn)有對(duì)象。通過getBeanFactory()方法訪問ApplicationContext的BeanFactory,該方法返回BeanFactory的DefaultListableBeanFactory實(shí)現(xiàn)。DefaultListableBeanFactory通過registerSingleton(..)和RegisterBeanDefinition(..)方法支持注冊(cè)功能。但是,典型的應(yīng)用程序只使用通過常規(guī)bean定義元數(shù)據(jù)定義的bean。
Bean命名
每個(gè)bean都有一個(gè)或多個(gè)標(biāo)識(shí)符。這些標(biāo)識(shí)符在承載bean的容器中必須是唯一的。bean通常只有一個(gè)標(biāo)識(shí)符。但是,如果它需要多個(gè)名稱,則可以將額外的名稱視為別名。
在基于XML的配置元數(shù)據(jù)中,可以使用id屬性和/或name屬性來指定bean標(biāo)識(shí)符。ID屬性允許您僅指定一個(gè)ID。通常,這些名稱是字母數(shù)字(“mybean”、“someservice”等),但它們也可以包含特殊字符。如果要為bean引入其他別名,還可以在name屬性中指定它們,用逗號(hào)(,),分號(hào)(;)或空格分隔。作為歷史記錄,在Spring3.1之前的版本中,id屬性被定義為xsd:id類型,這限制了可能的字符。從3.1開始,它被定義為xsd:string類型。注意,bean id的唯一性仍然由容器強(qiáng)制實(shí)現(xiàn),盡管不再由XML解析器實(shí)現(xiàn)。
如果不顯式地提供名稱或ID,容器將為該bean生成一個(gè)唯一的名稱。但是,如果希望通過使用ref元素或服務(wù)定位器樣式的查找來按名稱引用該bean,則必須提供一個(gè)名稱。
Bean定義外部實(shí)現(xiàn)別名
使用<alias/>元素來實(shí)現(xiàn)。
#name屬性用于內(nèi)部,alias屬性用于外部。
<alias name="fromName" alias="toName"/>
#下面3個(gè)名稱都指向同一個(gè)Bean對(duì)象。
<alias name="myApp-dataSource" alias="subsystemA-dataSource"/>
<alias name="myApp-dataSource" alias="subsystemB-dataSource"/>
Bean實(shí)例化
Bean Definition本質(zhì)上是創(chuàng)建一個(gè)或多個(gè)對(duì)象的方法。當(dāng)被詢問時(shí),容器會(huì)查看命名bean的配方,并使用由該bean定義封裝的配置元數(shù)據(jù)來創(chuàng)建(或獲取)實(shí)際對(duì)象。
如果使用基于XML的配置元數(shù)據(jù),則指定要在<bean/>元素的class屬性中實(shí)例化的對(duì)象的類型(或類)。這個(gè)類屬性(在內(nèi)部是BeanDefinition實(shí)例上的類屬性)通常是強(qiáng)制的。可以通過以下兩種方式之一使用Class屬性:
- 類全限定名,使用new創(chuàng)建
- 對(duì)象工廠類全限定名,使用工廠方法創(chuàng)建
內(nèi)部類的名稱采用binary name,例如:com.example.SomeThing$OtherThing
構(gòu)造函數(shù)實(shí)例化
<bean id="exampleBean" class="examples.ExampleBean"/>
<bean name="anotherExample" class="examples.ExampleBeanTwo"/>
靜態(tài)工廠方法實(shí)例化
<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;
??? }
}
實(shí)例工廠方法實(shí)例化
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
??? <!-- inject any dependencies required by this locator bean -->
</bean>
#2個(gè)Bean分別通過一個(gè)examples.DefaultServiceLocator實(shí)例的2個(gè)實(shí)例方法構(gòu)建。
<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;
??? }
}
???
依賴
依賴注入
在Spring 框架中,主要有以下兩種注入方式。
- 構(gòu)造函數(shù)注入
- setter注入
構(gòu)造函數(shù)注入
構(gòu)造函數(shù)方案
package x.y;
public class ThingOne {
??? public ThingOne(ThingTwo thingTwo, ThingThree thingThree) {
??????? // ...
??? }
}
<beans>
??? <bean id="beanOne" class="x.y.ThingOne">
??????? <constructor-arg ref="beanTwo"/>
??????? <constructor-arg ref="beanThree"/>
??? </bean>
??? <bean id="beanTwo" class="x.y.ThingTwo"/>
??? <bean id="beanThree" class="x.y.ThingThree"/>
</beans>
?
package examples;
public class ExampleBean {
??? // Number of years to calculate the Ultimate Answer
??? private int years;
??? // The Answer to Life, the Universe, and Everything
??? private String ultimateAnswer;
??? public ExampleBean(int years, String ultimateAnswer) {
??????? this.years = years;
??????? this.ultimateAnswer = ultimateAnswer;
??? }
}
構(gòu)造器參數(shù)類型匹配
<bean id="exampleBean" class="examples.ExampleBean">
??? <constructor-arg type="int" value="7500000"/>
??? <constructor-arg type="java.lang.String" value="42"/>
</bean>
構(gòu)造器參數(shù)索引
<bean id="exampleBean" class="examples.ExampleBean">
??? <constructor-arg index="0" value="7500000"/>
??? <constructor-arg index="1" value="42"/>
</bean>
構(gòu)造器參數(shù)名稱
<bean id="exampleBean" class="examples.ExampleBean">
??? <constructor-arg name="years" value="7500000"/>
??? <constructor-arg name="ultimateAnswer" value="42"/>
</bean>
由于編譯時(shí)參數(shù)名稱信息會(huì)丟失,因此要么在編譯時(shí)打開debug標(biāo)志,要么使用@ConstructorProperties?
package examples;
public class ExampleBean {
??? // Fields omitted
??? @ConstructorProperties({"years", "ultimateAnswer"})
??? public ExampleBean(int years, String ultimateAnswer) {
??????? this.years = years;
??????? this.ultimateAnswer = ultimateAnswer;
??? }
}
setter注入
基于setter方法的DI 是在通過調(diào)用無參數(shù)構(gòu)造函數(shù)或無參數(shù)靜態(tài)工廠方法來實(shí)例化bean 后,通過容器調(diào)用bean 的setter 方法完成的。
方式有Xml,Java注解(@Component,@Bean)
<bean id="exampleBean" class="examples.ExampleBean">
??? <!-- setter injection using the nested ref element -->
??? <property name="beanOne">
??????? <ref bean="anotherExampleBean"/>
??? </property>
??? <!-- setter injection using the neater ref attribute -->
??? <property name="beanTwo" ref="yetAnotherBean"/>
??? <property name="integerProperty" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
依賴處理過程
- ApplicationContext 根據(jù)元數(shù)據(jù)創(chuàng)建和初始化
- 對(duì)于每個(gè)bean,其依賴項(xiàng)都以屬性、構(gòu)造函數(shù)參數(shù)或靜態(tài)工廠方法的參數(shù)的形式表示
- 每個(gè)屬性或構(gòu)造函數(shù)參數(shù)是實(shí)際值或者是另一個(gè)bean的引用。
- 作為值的每個(gè)屬性或構(gòu)造函數(shù)參數(shù)都將從其指定的格式轉(zhuǎn)換為該屬性或構(gòu)造函數(shù)參數(shù)的實(shí)際類型。默認(rèn)情況下,Spring可以將以字符串格式提供的值轉(zhuǎn)換為所有內(nèi)置類型,如int、long、string、boolean等。
配置詳解
直接賦值
直接賦值支持字符串、原始類型的數(shù)據(jù)。
元素<property/>中的value 屬性允許以對(duì)人友好、易讀的形式配置屬性或構(gòu)造參數(shù)。Spring 的便利之處就是將這些字符串的值轉(zhuǎn)換為指定的類型。
String:
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
??? <!-- results in a setDriverClassName(String) call -->
??? <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
??? <property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
??? <property name="username" value="root"/>
??? <property name="password" value="masterkaoli"/>
</bean>
命名空間前綴
<beans xmlns="http://www.springframework.org/schema/beans"
??? xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
??? xmlns:p="http://www.springframework.org/schema/p"
??? xsi:schemaLocation="http://www.springframework.org/schema/beans
??? https://www.springframework.org/schema/beans/spring-beans.xsd">
??? <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
??????? destroy-method="close"
??????? p:driverClassName="com.mysql.jdbc.Driver"
??????? p:url="jdbc:mysql://localhost:3306/mydb"
??????? p:username="root"
??????? p:password="masterkaoli"/>
</beans>
java.util.Properties
<bean id="mappings"
??? class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
??? <!-- typed as a java.util.Properties -->
??? <property name="properties">
??????? <value>
??????????? jdbc.driver.className=com.mysql.jdbc.Driver
??????????? jdbc.url=jdbc:mysql://localhost:3306/mydb
??????? </value>
??? </property>
</bean>
?
idref
idref元素用來將容器內(nèi)其它bean的id傳給<constructor-arg/> 或 <property/>元素,同時(shí)提供錯(cuò)誤驗(yàn)證功能,減少配置的書寫錯(cuò)誤機(jī)率。除了<idref bean=""/>,如果被引用的bean在同一個(gè)xml文件中,且bean的名字就是bean的id,除了可以使用<idref local=""/>,此屬性允許xml解析器在解析XML的時(shí)候?qū)σ玫腷ean進(jìn)行驗(yàn)證。其實(shí)idref就跟value一樣,只是將某個(gè)字符串注入到屬性或者構(gòu)造函數(shù)中,只不過注入的是某個(gè)bean定義的id屬性值。
?
<bean id="theTargetBean" class="..."/>
<bean id="theClientBean" class="...">
??? <property name="targetName">
??????? <idref bean="theTargetBean"/>
??? </property>
</bean>
#等同于:
<bean id="client" class="...">
??? <property name="targetName" value="theTargetBean"/>
</bean>
?
引用其他bean
<ref>元素通過id或者name引用其他bean,可以通過bean,local,parent屬性設(shè)置。
<ref bean="someBean"/>??
parent屬性引用當(dāng)前container的父container,僅存在于層次容器中。
<bean id="accountService" class="com.something.SimpleAccountService">
??? <!-- insert dependencies as required as here -->
</bean>
<bean id="accountService" <!-- bean name is the same as the parent bean -->
??? class="org.springframework.aop.framework.ProxyFactoryBean">
??? <property name="target">
??????? <ref parent="accountService"/> <!-- notice how we refer to the parent bean -->
??? </property>
??? <!-- insert other configuration and dependencies as required here -->
</bean>
內(nèi)部Bean
<bean id="outer" class="...">
??? <!-- instead of using a reference to a target bean, simply define the target bean inline -->
??? <property name="target">
??????? <bean class="com.example.Person"> <!-- this is the inner bean -->
??????????? <property name="name" value="Fiona Apple"/>
??????????? <property name="age" value="25"/>
??????? </bean>
??? </property>
</bean>
內(nèi)部bean是匿名的,并且不可以被其他bean引用。
集合
<list/>, <set/>, <map/> 和 <props/> 元素對(duì)應(yīng)Java集合類型:List, Set, Map, 和Properties
<bean id="moreComplexObject" class="example.ComplexObject">
??? <!-- results in a setAdminEmails(java.util.Properties) call -->
??? <property name="adminEmails">
??????? <props>
??????????? <prop key="administrator">administrator@example.org</prop>
??????????? <prop key="support">support@example.org</prop>
??????????? <prop key="development">development@example.org</prop>
??????? </props>
??? </property>
??? <!-- results in a setSomeList(java.util.List) call -->
??? <property name="someList">
??????? <list>
??????????? <value>a list element followed by a reference</value>
??????????? <ref bean="myDataSource" />
??????? </list>
??? </property>
??? <!-- results in a setSomeMap(java.util.Map) call -->
??? <property name="someMap">
??????? <map>
??????????? <entry key="an entry" value="just some string"/>
??????????? <entry key ="a ref" value-ref="myDataSource"/>
??????? </map>
??? </property>
??? <!-- results in a setSomeSet(java.util.Set) call -->
??? <property name="someSet">
??????? <set>
??????????? <value>just some string</value>
??????????? <ref bean="myDataSource" />
??????? </set>
??? </property>
</bean>
map的key或value或者是集合的value都可以配置為下列元素
bean | ref | idref | list | set | map | props | value | null
集合合并
不能合并不同類型的集合
Null及空字符串值
<bean class="ExampleBean">
??? <property name="email" value=""/>
</bean>
<bean class="ExampleBean">
??? <property name="email">
??????? <null/>
??? </property>
</bean>
?
XML短命名空間
p 命名空間令開發(fā)者可以使用bean的屬性,而不用使用嵌套的<property/>元素就能描述開發(fā)者想要注入的依賴
<beans xmlns="http://www.springframework.org/schema/beans"
??? xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
??? xmlns:p="http://www.springframework.org/schema/p"
??? xsi:schemaLocation="http://www.springframework.org/schema/beans
??????? https://www.springframework.org/schema/beans/spring-beans.xsd">
??? <bean name="classic" class="com.example.ExampleBean">
??????? <property name="email" value="someone@somewhere.com"/>
??? </bean>
??? <bean name="p-namespace" class="com.example.ExampleBean"???????? p:email="someone@somewhere.com"/>
</beans>
<beans xmlns="http://www.springframework.org/schema/beans"
??? xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
??? xmlns:p="http://www.springframework.org/schema/p"
??? xsi:schemaLocation="http://www.springframework.org/schema/beans
??????? https://www.springframework.org/schema/beans/spring-beans.xsd">
??? <bean name="john-classic" class="com.example.Person">
??????? <property name="name" value="John Doe"/>
??????? <property name="spouse" ref="jane"/>
??? </bean>
??? <bean name="john-modern"
??????? class="com.example.Person"
??????? p:name="John Doe"
??????? p:spouse-ref="jane"/>
??? <bean name="jane" class="com.example.Person">
??????? <property name="name" value="Jane Doe"/>
??? </bean>
</beans>
?
與p命名空間類似, c命名空間允許內(nèi)聯(lián)的屬性來配置構(gòu)造參數(shù), 而不用使用constructor-arg元素。c 命名空間是在Spring 3.1 版本首次引入的.
?
<beans xmlns="http://www.springframework.org/schema/beans"
??? xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
??? xmlns:c="http://www.springframework.org/schema/c"
??? xsi:schemaLocation="http://www.springframework.org/schema/beans
??????? https://www.springframework.org/schema/beans/spring-beans.xsd">
??? <bean id="beanTwo" class="x.y.ThingTwo"/>
??? <bean id="beanThree" class="x.y.ThingThree"/>
??? <!-- traditional declaration with optional argument names -->
??? <bean id="beanOne" class="x.y.ThingOne">
??????? <constructor-arg name="thingTwo" ref="beanTwo"/>
??????? <constructor-arg name="thingThree" ref="beanThree"/>
??????? <constructor-arg name="email" value="something@somewhere.com"/>
??? </bean>
??? <!-- c-namespace declaration with argument names -->
??? <bean id="beanOne" class="x.y.ThingOne" c:thingTwo-ref="beanTwo"
??????? c:thingThree-ref="beanThree" c:email="something@somewhere.com"/>
</beans>
索引方式
<!-- c-namespace index declaration -->
<bean id="beanOne" class="x.y.ThingOne" c:_0-ref="beanTwo" c:_1-ref="beanThree"
??? c:_2="something@somewhere.com"/>
復(fù)合屬性名稱
開發(fā)者可以在配置屬性時(shí)配置復(fù)合屬性的名稱,只要確保除了最后一個(gè)屬性外,其余的屬性值都不能為Null 。
<bean id="something" class="things.ThingOne">
??? <property name="fred.bob.sammy" value="123" />??
</bean>
fred,bob屬性必須不為null。
depends-on
有時(shí)bean 之間的依賴關(guān)系不是直接關(guān)聯(lián)的,如需要調(diào)用類的靜態(tài)實(shí)例化工具來觸發(fā), 一個(gè)典型的例子是數(shù)據(jù)庫驅(qū)動(dòng)注冊(cè)。
depends-on 屬性會(huì)使明確的、強(qiáng)迫依賴的bean 在引用之前就會(huì)初始化
<bean id="beanOne" class="ExampleBean" depends-on="manager"/>
<bean id="manager" class="ManagerBean" />
如果想要依賴多個(gè)bean ,可以提供多個(gè)名稱作為depends-on 的值,以逗號(hào)、空格或分號(hào)分割
<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
??? <property name="manager" ref="manager" />
</bean>
<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />
延遲加載bean
默認(rèn)情況下,ApplicationContext會(huì)在實(shí)例化的過程中創(chuàng)建和配置所有的單例bean。開發(fā)者可以通過將bean 標(biāo)記為延遲加載阻止預(yù)初始化。
延遲初始化的bean 會(huì)通知IoC 不要讓bean 預(yù)初始化,而是在被引用時(shí)才會(huì)實(shí)例化。在XML 中,可以通過<bean>元素的lazy-init屬性來控制這個(gè)行為
<bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/>
<bean name="not.lazy" class="com.something.AnotherBean"/>
如果一個(gè)延遲加載的bean作為另外一個(gè)非延遲加載的單例bean 的依賴而存在,延遲加載的bean仍然會(huì)在ApplicationContext 啟動(dòng)時(shí)加載。因?yàn)樽鳛閱卫齜ean的依賴,它會(huì)隨著單例bean 的實(shí)例化而實(shí)例化。
開發(fā)者可以通過使用<beans> 的default-lazy-init屬性在容器層次控制bean是否延遲初始化
<beans default-lazy-init="true">
??? <!-- no beans will be pre-instantiated... -->
</beans>
自動(dòng)裝配
Spring容器可以自動(dòng)裝配協(xié)作bean之間的關(guān)系。通過檢查applicationContext的內(nèi)容,可以讓Spring自動(dòng)解析bean的合作者(其他bean)。自動(dòng)裝配具有以下優(yōu)點(diǎn):
- 顯著減少指定屬性或構(gòu)造函數(shù)參數(shù)的需要
- 隨著對(duì)象的發(fā)展更新配置。
Xml配置使用<bean>的autowire屬性,有4種模式:
-
no:默認(rèn)值,不自動(dòng),使用ref元素。不建議修改默認(rèn)值。
-
byName:通過名稱
-
byType:通過類型
-
constructor:構(gòu)造函數(shù)
自動(dòng)裝配的限制與缺點(diǎn)
- property和constructor-arg顯式依賴項(xiàng)會(huì)覆蓋autowired。不能autowire簡單屬性,如基本類型、字符串和類(以及此類簡單屬性的數(shù)組)。這種限制是由設(shè)計(jì)造成的。
- autowired不如顯式裝配精確。
- 生成文檔的工具可能無法獲得接線信息。
- 如果沒有唯一的bean定義可用,則引發(fā)異常。
裝配時(shí)排除bean
autowire-candidate設(shè)置為false,只影響byType類型的自動(dòng)裝配。<beans> 的default-autowire-candidates屬性可以設(shè)置哪些bean自動(dòng)裝配,支持通配符*,?? 例如:*Repository
方法注入
大多數(shù)的bean在應(yīng)用場景中都是單例的。當(dāng)這個(gè)單例的bean 需要和非單例的bean聯(lián)合使用時(shí),有可能會(huì)因?yàn)椴煌琤ean的生命周期不同而產(chǎn)生問題。假設(shè)單例的bean A 在每個(gè)方法調(diào)用中使用了非單例的bean B ,由于容器只會(huì)創(chuàng)建bean A 一次,而只有一個(gè)機(jī)會(huì)來配置屬性。那么容器就無法給bean A 每次都提供一個(gè)新的bean B 的實(shí)例。
一個(gè)解決方案就是放棄一些IoC 。開發(fā)者可以通過實(shí)現(xiàn)ApplicationContextAware接口,調(diào)用ApplicationContext的getBean("B")方法在bean A 需要新的實(shí)例時(shí)來獲取新的bean B實(shí)例
public class CommandManager implements ApplicationContextAware {
??? private ApplicationContext applicationContext;
??? public Object process(Map commandState) {
??????? // grab a new instance of the appropriate Command
??????? Command command = createCommand();
??????? // set the state on the (hopefully brand new) Command instance
??????? command.setState(commandState);
??????? return command.execute();
??? }
??? protected Command createCommand() {
??????? // notice the Spring API dependency!
??????? return this.applicationContext.getBean("command", Command.class);
??? }
??? public void setApplicationContext(
??????????? ApplicationContext applicationContext) throws BeansException {
??????? this.applicationContext = applicationContext;
??? }
}
當(dāng)然,這種方式也有一些弊端,就是需要依賴于Spring的API 。這在一定程序上對(duì)Spring 框架存在耦合。那么是存還有其他方案來避免這些弊端呢?答案是肯定的。
Spring 框架提供了<lookup-method>和<replace-method>來解決上述問題。
Lookup Method
lookup-method注入是Spring 動(dòng)態(tài)改變bean中方法的實(shí)現(xiàn)。方法執(zhí)行返回的對(duì)象,是使用了CGLIB 庫的方法, 重新生成子類,重寫配置的方法和返回對(duì)象,達(dá)到動(dòng)態(tài)改變的效果。
- 為了使這個(gè)動(dòng)態(tài)子類化工作,SpringBean容器子類不能是final類,要重寫的方法也不能是final類。
- 單元測試具有抽象方法的類需要您自己對(duì)類進(jìn)行子類化,并提供抽象方法的存根實(shí)現(xiàn)。
- 組件掃描還需要具體的方法,這需要具體的類別來獲取。
- 另一個(gè)關(guān)鍵限制是查找方法不適用于工廠方法,尤其不適用于配置類中的@bean方法,因?yàn)樵谶@種情況下,容器不負(fù)責(zé)創(chuàng)建實(shí)例,因此無法動(dòng)態(tài)創(chuàng)建運(yùn)行時(shí)生成的子類。
?
package fiona.apple;
public abstract class CommandManager {
??? public Object process(Object commandState) {
??????? // 需要一個(gè)實(shí)例
??????? Command command = createCommand();
??????? command.setState(commandState);
??????? return command.execute();
??? }
??? //此方法返回一個(gè)實(shí)例,抽象方法,具體實(shí)現(xiàn)在哪里呢?
??? protected abstract Command createCommand();
}
在上面代碼中,將要被注入的方法的類為CommandManager ,被注入方法格式為:
<public|protected> [abstract] <return-type> theMethodName(no-arguments);
?
XML配置方式:
<!-- a stateful bean deployed as a prototype (non-singleton) ,如果設(shè)置成了單例,每次返回同一實(shí)例-->
<bean id="myCommand" class="fiona.apple.AsyncCommand" scope="prototype">
??? <!-- inject dependencies here as required -->
</bean>
<!-- commandProcessor uses statefulCommandHelper -->
<bean id="commandManager" class="fiona.apple.CommandManager">
??? <lookup-method name="createCommand" bean="myCommand"/>
</bean>
Lookup注解方式:
public abstract class CommandManager {
??? public Object process(Object commandState) {
??????? Command command = createCommand();
??????? command.setState(commandState);
??????? return command.execute();
??? }
??? @Lookup("myCommand")
??? protected abstract Command createCommand();
}
?
replace-method注入
replaced-method 注入是Spring 動(dòng)態(tài)改變bean中方法的實(shí)現(xiàn)。需要改變的方法,使用Spring內(nèi)原有其他類(需要繼承接口org.springframework.beans.factory.support.MethodReplacer )的邏輯替換這個(gè)方法。通過改變方法執(zhí)行邏輯來動(dòng)態(tài)改變方法。內(nèi)部實(shí)現(xiàn)為使用CGLIB 方法,重新生成子類,重寫配置的方法和返回對(duì)象,達(dá)到動(dòng)態(tài)改變的效果。
示例:
public class MyValueCalculator {
? //computeValue方法將會(huì)被替換
??? public String computeValue(String input) {
??????? // some real code...
??? }
??? // some other methods...
}
public class ReplacementComputeValue implements MethodReplacer {
??? public Object reimplement(Object o, Method m, Object[] args) throws Throwable {
??????? // get the input value, work with it, and return a computed result
??????? String input = (String) args[0];
??????? ...
??????? return ...;
??? }
}
XML配置:
<bean id="myValueCalculator" class="x.y.z.MyValueCalculator">
??? <!-- arbitrary method replacement -->
??? <replaced-method name="computeValue" replacer="replacementComputeValue">
<!-- arg-type的值可以為實(shí)際類型的子串,因?yàn)榉椒▍?shù)個(gè)數(shù)已經(jīng)可以區(qū)別出大多數(shù)方法了 -->
??????? <arg-type>String</arg-type>
??? </replaced-method>
</bean>
<bean id="replacementComputeValue" class="a.b.c.ReplacementComputeValue"/>
注解配置
無
Bean Scope
Bean Scope值:
| Scope | Description |
| singleton | 單例 |
| prototype | 多例 |
| request | 每個(gè)HTTP請(qǐng)求一個(gè)實(shí)例 |
| session | 每個(gè)Session一個(gè)實(shí)例 |
| application | 每個(gè)Application一個(gè)實(shí)例 |
| websocket | 每個(gè)WebSocket一個(gè)實(shí)例 |
Request, Session, Application, WebSocket Scopes
request、session、application 及websocket 這幾個(gè)scope 都是只有在基于Web 的ApplicationContext實(shí)現(xiàn)(如XmlWebApplicationContext)中才能使用。如果開發(fā)者僅僅在常規(guī)的Spring IoC 容器(如ClassPathXmlApplicationContext )中使用這些scope ,那么將會(huì)拋出一個(gè)IllegalStateException 來說明使用了scope 。
初始化Web Configuration
為了能夠使用request 、session 、application 及websocket 這幾個(gè)scope , 需要在配置bean 之前做一些基礎(chǔ)的配置。而對(duì)于標(biāo)準(zhǔn)的scope,如singleton 及prototype ,是無須這些基礎(chǔ)的配置的。
具體如何配置取決于Servlet的環(huán)境。
如果開發(fā)者使用了Spring Web MVC 框架,那么每一個(gè)請(qǐng)求都會(huì)通過Spring 的DispatcherServlet 或DispatcherPortlet 來處理,也就沒有其他特殊的初始化配置c DispatcherServlet 和DispatcherPortlet 己經(jīng)包含了相關(guān)的狀態(tài)。
如果使用Servlet 2.5 的Web 容器,請(qǐng)求不是通過Spring 的Dispatcherservlet (如JSF 或Struts )來處理,那么開發(fā)者需要注冊(cè)org.springframework.web.context.request.RequestContextListener 或ServletRequestListener。而在Servlet 3.0以后,這些都能夠通過WebApplicationlnitializer 接口來實(shí)現(xiàn)。如果是一些舊版本的容器,可以在web.xml中增加以下的Listener 聲明。
<web-app>
??? ...
??? <listener>
??????? <listener-class>
??????????? org.springframework.web.context.request.RequestContextListener
??????? </listener-class>
??? </listener>
??? ...
</web-app>
也可以考慮使用Spring的RequestContextFilter。Filter 的映射取決于Web 應(yīng)用的配置:
<web-app>
??? ...
??? <filter>
??????? <filter-name>requestContextFilter</filter-name>
??????? <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
??? </filter>
??? <filter-mapping>
??????? <filter-name>requestContextFilter</filter-name>
??????? <url-pattern>/*</url-pattern>
??? </filter-mapping>
??? ...
</web-app>
DispatcherServlet 、RequestContextListener 及RequestContextFilter 本質(zhì)上完全一致,都是綁定請(qǐng)求對(duì)象到服務(wù)請(qǐng)求的Thread 上。這才使得bean在之后的調(diào)用鏈上可見。
Request scope
<bean id="loginAction" class="com.something.LoginAction" scope="request"/>
@RequestScope
@Component
public class LoginAction {
??? // ...
}
Session Scope
<bean id="userPreferences" class="com.something.UserPreferences" scope="session"/>
@SessionScope
@Component
public class UserPreferences {
??? // ...
}
?
Application Scope
<bean id="appPreferences" class="com.something.AppPreferences" scope="application"/>
@ApplicationScope
@Component
public class AppPreferences {
??? // ...
}
當(dāng)把一個(gè)scope的bean注入到一個(gè)更長scope的bean時(shí),建議用AOP Proxy代替。使用<aop:scoped-proxy/>
自定義Scope
可以通過實(shí)現(xiàn)org.springframework.beans.factory.config.Scope 接口實(shí)現(xiàn)自定義scope
自定義Bean生命周期
spring框架提供了許多接口,您可以使用這些接口來定制bean的生命周期。
- Lifecycle Callbacks
- ApplicationContextAware和BeanNameAware
- Other Aware Interfaces
Lifecycle Callbacks
可以通過實(shí)現(xiàn)InitializingBean 和DisposableBean接口來管理container的生命周期,容器調(diào)用前者afterpropertiesset(),為調(diào)用后者的destroy(),以便bean在初始化和銷毀bean時(shí)執(zhí)行某些操作。使用這些接口的一個(gè)弊端就是與Spring API 產(chǎn)生了耦合。
JSR-250 的@PostConstruct 和@PreDestroy 注解就是現(xiàn)代Spring 應(yīng)用生命周期回調(diào)的最佳實(shí)踐。使用這些注解意味著bean 不會(huì)再耦合在Spring 特定的接口上。
如果開發(fā)者不想使用JSR-250的注解,仍然可以考慮使用init-method 和destroy-method 的定義來解耦Spring 接口。
從內(nèi)部來說,Spring 框架使用BeanPostProcessor的實(shí)現(xiàn)來處理接口的回調(diào), BeanPostProcessor能夠找到并調(diào)用合適的方法。如果開發(fā)者需要定制一些Spring并不直接提供的生命周期行為,可以考慮自行實(shí)現(xiàn)一個(gè)BeanPostProcessor。
除了初始化回調(diào)和銷毀回調(diào), Spring 管理的對(duì)象也實(shí)現(xiàn)了Lifecycle 接口讓管理的對(duì)象在容器的生命周期內(nèi)啟動(dòng)或關(guān)閉。
初始化回調(diào)
org.springframework.beans.factory.InitializingBean接口允許bean在所有必要依賴配置完成后執(zhí)行初始化bean的操作。InitializingBean接口中定義了一個(gè)方法:
void afterPropertiesSet() throws Exception;
建議開發(fā)者不要使用InitializingBean接口,否則會(huì)將代碼耦合到Spring 的特定接口之上。
Xml方式:
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
public class ExampleBean {
??? public void init() {
??????? // do some initialization work
??? }
}
Java注解:
@Configuration
public class AppConfig {
??? @Bean(initMethod = "init")
??? public BeanOne beanOne() {
??????? return new BeanOne();
??? }
}
銷毀回調(diào)
實(shí)現(xiàn)了org.springframework.beans.factory.DisposableBean接口的bean就能讓容器通過回調(diào)來銷毀bean 所引用的資源。DisposableBean接口包含一個(gè)方法destroy(),
void destroy() throws Exception;
不建議開發(fā)者使用DisposableBean 回調(diào)接口, 否則會(huì)將開發(fā)者的代碼耦合到Spring 代碼上。
Xml方式:
<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
public class ExampleBean {
??? public void cleanup() {
??????? // do some destruction work (like releasing pooled connections)
??? }
}
java注解:
@Configuration
public class AppConfig {
??? @Bean(initMethod = "init")
??? public BeanOne beanOne() {
??????? return new BeanOne();
??? }
??? @Bean(destroyMethod = "cleanup")
??? public BeanTwo beanTwo() {
??????? return new BeanTwo();
??? }
}
默認(rèn)初始化回調(diào)與銷毀回調(diào)
Spring可以自動(dòng)識(shí)別init()方法作為初始化回調(diào)方法,destroy()方法作為銷毀回調(diào)方法,
<beans default-init-method="init">
??? <bean id="blogService" class="com.something.DefaultBlogService">
??????? <property name="blogDao" ref="blogDao" />
??? </bean>
</beans>
當(dāng)配置了default-init-method屬性,則如果一個(gè)類定義了指定的方法,則會(huì)在何時(shí)的時(shí)候調(diào)用此初始化回調(diào)。類似,default-destroy-method輸定定義了默認(rèn)銷毀回調(diào)。默認(rèn)回調(diào)可以被init-method,destroy-method設(shè)置覆蓋。
spring容器保證在bean提供所有依賴項(xiàng)之后立即調(diào)用已配置的初始化回調(diào)。因此,初始化回調(diào)在原始bean引用調(diào)用,這意味著aop攔截器等尚未應(yīng)用于bean。
組合生命周期機(jī)制
在Spring 2.5 版本之后,開發(fā)者有以下3種選擇來控制bean 的生命周期行為。
- InitializingBean和DisposableBean接口
- init()和destroy()
- @PostConstruct和@PreDestroy
如果一個(gè)bean 配置了多個(gè)生命周期機(jī)制,并且含有不同的方法名,執(zhí)行的順序如下。
- ①包含@PostConstruct 注解的方法。
- ②在InitializingBean 接口中的afterPropertiesSet()方法。
- ③自定義的init()方法。
銷毀方法的執(zhí)行順序與初始化的執(zhí)行順序相同。
- ①包含@PreDestroy 注解的方法。
- ②在DisposableBean接口中的destroy()方法。
- ③自定義的destory()方法。
開啟和關(guān)閉回調(diào)
在非Web應(yīng)用環(huán)境中優(yōu)雅地關(guān)閉Spring Ioc窯器
如果開發(fā)者在非Web應(yīng)用環(huán)境使用Spring IoC 容器,如在桌面客戶端的環(huán)境下,開發(fā)者需要在JVM上注冊(cè)一個(gè)關(guān)閉的鉤子,以確保在關(guān)閉Spring IoC容器時(shí)能夠調(diào)用相關(guān)的銷毀方法來釋放掉引用的資源。當(dāng)然,開發(fā)者也必須要正確地配置和實(shí)現(xiàn)那些銷毀回調(diào)
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public final class Boot {
??? public static void main(final String[] args) throws Exception {
??????? ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
??????? // add a shutdown hook for the above context...
??????? ctx.registerShutdownHook();
??????? // app runs here...
??????? // main method exits, hook is called prior to the app shutting down...
??? }
}
ApplicationContextAware和BeanNameAware
當(dāng)ApplicationContext 在創(chuàng)建實(shí)現(xiàn)了org.springframework.context.ApplicationContextAware接口的對(duì)象時(shí),該對(duì)象的實(shí)例會(huì)包含一個(gè)到ApplicationContext 的引用。
public interface ApplicationContextAware {
??? void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
這樣bean就能夠通過編程的方式操作和創(chuàng)建ApplicationContext
當(dāng)ApplicationContext 創(chuàng)建了一個(gè)實(shí)現(xiàn)了org.springframework.beans.factory.BeanNameAware接口的類,那么這個(gè)類就可以針對(duì)其名稱進(jìn)行配置
public interface BeanNameAware {
??? void setBeanName(String name) throws BeansException;
}
這個(gè)回調(diào)的調(diào)用發(fā)生在屬性配置完以后,在初始化回調(diào)之前.
Other Aware Interfaces
| 名稱 | 注入的依賴 | 詳細(xì)解釋 |
| ApplicationContextAware | 聲明的ApplicationContext. | ApplicationContextAware and BeanNameAware |
| ApplicationEventPublisherAware | ApplicationContext中的事件發(fā)布器. | Additional Capabilities of the ApplicationContext |
| BeanClassLoaderAware | 加載bean的類加載器 | Instantiating Beans |
| BeanFactoryAware | 聲明的BeanFactory. | ApplicationContextAware and BeanNameAware |
| BeanNameAware | bean的Name | ApplicationContextAware and BeanNameAware |
| BootstrapContextAware | 容器運(yùn)行的資源適配器BootstrapContext 僅JCA環(huán)境下有效 | JCA CCI |
| LoadTimeWeaverAware | 加載期間處理類的weaver | Load-time Weaving with AspectJ in the Spring Framework |
| MessageSourceAware | 解析消息的配置策略 | Additional Capabilities of the ApplicationContext |
| NotificationPublisherAware | Spring JMX 通知發(fā)布器 | Notifications |
| ResourceLoaderAware | 配置的資源加載器 | Resources |
| ServletConfigAware | 容器當(dāng)前運(yùn)行的 ServletConfig,僅在web下的Spring ApplicationContext有效. | Spring MVC |
| ServletContextAware | 容器當(dāng)前運(yùn)行的 ServletContext,僅在web下的Spring ApplicationContext有效. | Spring MVC |
Bean定義繼承
如果編程式地使用ApplicationContext接口,子bean 的定義可以通過ChildBeanDefinition 類來表示。更常用在ClassPathXmlApplicationContext中聲明式地配置bean的定義。
<bean id="inheritedTestBean" abstract="true"
??????? class="org.springframework.beans.TestBean">
??? <property name="name" value="parent"/>
??? <property name="age" value="1"/>
</bean>
<bean id="inheritsWithDifferentClass"
??????? class="org.springframework.beans.DerivedTestBean"
??????? parent="inheritedTestBean" init-method="initialize"> ?
??? <property name="name" value="override"/>
??? <!-- the age property value of 1 will be inherited from parent -->
</bean>
子bean如果沒有指定class ,它將使用父bean定義的class ,也可以進(jìn)行重載。
子bean定義可以從父類繼承:
- scope
- constructor argument values
- property values
- method overrides from the parent
- add new values
會(huì)覆蓋父bean的包括:
- scope
- initialization method
- destroy method
- static factory method
總是使用子bean的:
- depends on
- autowire mode
- dependency check
- singleton
- lazy init
父bean定義沒有明確地指出所屬的類,那么標(biāo)記父bean定義為abstract 是必需的
<bean id="inheritedTestBeanWithoutClass" abstract="true">
??? <property name="name" value="parent"/>
??? <property name="age" value="1"/>
</bean>
嘗試獨(dú)立地使用這樣一個(gè)abstract的父bean,把它作為另一個(gè)bean引用,或者根據(jù)這個(gè)父bean的id顯式調(diào)用getBean()方法,將會(huì)返回一個(gè)錯(cuò)誤。類似地,容器內(nèi)部的preInstantiateSingletons()方法,也忽略定義為抽象的bean定義.
?
?
總結(jié)
以上是生活随笔為你收集整理的Spring--IoC(1)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spring-tx
- 下一篇: Spring--IoC(2)