1 spring核心IoC
spring源碼版本 version 4.0.5
1.1 BeanFactory 和 ApplicationContext
spring IoC容器的核心的表現(xiàn)形式就是 BeanFactory和ApplicationContext
1.1.1 BeanFactory
- 可以通過(guò)getBean方法獲得指定的bean
- isSingleton 判斷指定的bean是不是單例的
主要是BeanFactory的接口中方法
其中有兩個(gè)BeanFactory的實(shí)現(xiàn)比較需要注意 DefaultListableBeanFactory
和AbstractAutowireCapableBeanFactory
巴帮。 使用比較多分飞。
1.1.2 ApplicationContext
其實(shí)使用編程的方式可以創(chuàng)建IoC,即創(chuàng)建factory 靶剑,然后對(duì)factory進(jìn)行各種設(shè)置再使用(參見(jiàn)本文1.2.2最后的示例)摸柄。但是spring提供了更加方便的ApplicationContext,同時(shí)還更加了一些額外的操作呻征。
- 支持不同的信息資源。ApplicationContext擴(kuò)展了MessageSource接口
- 訪問(wèn)資源。繼承自DefaultResourceLoader
- 支持應(yīng)用事件悠菜。繼承自接口ApplicationEventPublisher
- 附件服務(wù)
1.2 IoC 容器初始化過(guò)程
第一步:Resource定位過(guò)程。通過(guò)ResourceLoader的統(tǒng)一接口Resource找到BeanDefinition的資源定位败富。
第二步:BeanDefinition 載入悔醋。把用戶定義好的Bean轉(zhuǎn)換成IoC容器內(nèi)部的數(shù)據(jù)結(jié)構(gòu)BeanDefinition。
第三步:向IoC容器注冊(cè)這些BeanDefinition的過(guò)程兽叮。調(diào)用BeanDefinitionRegistry.registerBeanDefinition實(shí)現(xiàn)芬骄。這個(gè)注冊(cè)過(guò)程把載入過(guò)程中解析的BeanDefinition向IoC注冊(cè)。實(shí)際上IoC內(nèi)部是將BeanDefinition注入好一個(gè)HashMap中鹦聪,通過(guò)這個(gè)HashMap來(lái)持有這些BeabDefinition的數(shù)據(jù)账阻。
這個(gè)過(guò)程中不包含依賴注入,依賴注入和bean定義(BeanDefinition)的載入是兩個(gè)獨(dú)立的過(guò)程泽本。 依賴注入一般發(fā)生在第一次使用getBean獲取bean的時(shí)候淘太,但是如果bean配置了lazyinit的話,會(huì)提前初始化规丽,不用等到第一次getBean觸發(fā)蒲牧。
1.2.1 BeanDefinition的資源定位
看BeanDefinition的資源定位,以FileSystemXmlApplicationContext為例赌莺,查看一下過(guò)程造成。
FileSystemXmlApplicationContext的構(gòu)造方法中,refresh() 方法啟動(dòng)IoC容器雄嚣。 幾種ApplicationContext的子類都是在構(gòu)造方法中refresh里面啟動(dòng)容器的。
方法調(diào)用鏈路:
AbstractApplicationContext.refresh()-->obtainFreshBeanFactory()-->refreshBeanFactory-->AbstractRefreshableApplicationContext.refreshBeanFactory()-->loadBeanDefinitions-->AbstractXmlApplicationContext.loadBeanDefinitions()
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
// 通過(guò)config獲取
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
// 通過(guò)字符串獲取
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
如果得到是String[] configLocations 則會(huì)最后進(jìn)入到 AbstractBeanDefinitionReader的public int loadBeanDefinitions(String location, Set<Resource> actualResources)喘蟆。此方法內(nèi)部把String 轉(zhuǎn)換成Resource缓升。 整個(gè)獲取BeanDefinition的過(guò)程就結(jié)束了,定位BeanDefinition的主要目的就是把資源位置轉(zhuǎn)換成可以處理的Resource
上面兩個(gè)分支最后都是走如下路徑去加載BeanDefinition
AbsractBeanDefinitionReader.loadBeanDefinitions(Resource... resources) --> XmlBeanDefinitionReader.loadBeanDefinitions(Resource resource) (loadBeanDefinitions(EncodedResource encodedResource))
1.2.2 BeanDefinition的載入
在找到資源位子時(shí)候蕴轨,獲取到很多的Resources只有港谊,在需要根據(jù)資源類型,選擇不同類型的BeanDefinitionReader載入資源橙弱,例如Xml的配置文件歧寺,最后載入的時(shí)候就是XmlBeanDefinitionReader來(lái)執(zhí)行載入。
之前的說(shuō)到過(guò)棘脐,ApplicationContext的子類都是在構(gòu)造方法里面通過(guò)refresh方法啟動(dòng)容器的斜筐。所有BeanDefinition的資源定位和載入BeanDefinition的入口都是在refresh方法中。
核心入口:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
// refresh前準(zhǔn)備工作
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 通知子類調(diào)用內(nèi)部 refresh bean factory的方法 refreshBeanFactory(),
// 此refreshBeanFactory()是資源定位和載入的入口
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// 設(shè)置beanFactory的標(biāo)準(zhǔn)上下文特征
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// 設(shè)置beanFactory的后置處理
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 調(diào)用beanFactory的后處理器
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 注冊(cè)bean 后處理器蛀缝,在bean創(chuàng)建的過(guò)程中調(diào)用
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 初始化上下文的消息資源
initMessageSource();
// Initialize event multicaster for this context.
// 初始化上下文事件
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 利用子類初始化一些特殊bean
onRefresh();
// Check for listener beans and register them.
// 檢查監(jiān)聽(tīng)器并向容器注冊(cè)這些監(jiān)聽(tīng)器
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// 實(shí)例化所有(non-lazy-init)的單例組件
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// 最后一步顷链,發(fā)布容器,結(jié)束refresh過(guò)程
finishRefresh();
}
catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
// 防止單例組件占用資源屈梁,在異常中銷毀
destroyBeans();
// Reset 'active' flag.
// 設(shè)置'active'標(biāo)識(shí)
cancelRefresh(ex);
// Propagate exception to caller.
// 向外層調(diào)用這拋出異常
throw ex;
}
}
}
前面步驟和查找resource一樣嗤练,xml形式的配置文件榛了,最后走到XmlBeanDefinitionReader中(定位資源中有提到,最后進(jìn)入XmlBeanDefinitionReader.loadBeanDefinitions(EncodedResource encodedResource)),進(jìn)入如下方法:
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
// 將資源轉(zhuǎn)換成輸入流
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
// 在doLoadBeanDefinitions方法中實(shí)現(xiàn)BeanDefinition的載入
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
從輸入流中讀取bean的定義煞抬,從doLoadBeanDefinitions 方法進(jìn)入霜大,開(kāi)始載入BeanDefinition。在doLoadBeanDefinitions方法中通過(guò)InputSource和recource得到Document革答,緊接著調(diào)用registerBeanDefinitions战坤,實(shí)際調(diào)用到DefaultBeanDefinitionDocumentReader.registerBeanDefinitions-->doRegisterBeanDefinitions(root)
protected void doRegisterBeanDefinitions {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
Assert.state(this.environment != null, "Environment must be set for evaluating profiles");
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!this.environment.acceptsProfiles(specifiedProfiles)) {
return;
}
}
// 任何嵌套的 <beans> 元素將會(huì)導(dǎo)致這個(gè)方法的循環(huán),
// 為了正確的傳播和保存<beans>的default-*屬性蝗碎,追蹤當(dāng)前代理(可能為null)湖笨。
// 創(chuàng)建一個(gè)新的代理對(duì)象,指向原來(lái)對(duì)象來(lái)達(dá)到回滾的目的蹦骑,最終重置this.delegate到原來(lái)的對(duì)象慈省。
// 整個(gè)的表現(xiàn)模擬了一個(gè)代理?xiàng)#恍枰粋€(gè)代理
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(this.readerContext, root, parent);
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
再進(jìn)入parseBeanDefinitions解析眠菇。在parseBeanDefinitions中边败,如果是默認(rèn)的namespace就進(jìn)入parseDefaultElement(ele, delegate)
,如果不是就進(jìn)入delegate.parseCustomElement(ele)
,在parseDefaultElement中分別解析 import
、alias
捎废、bean
笑窜、beans
,其中beans會(huì)進(jìn)入遞歸,調(diào)用doRegisterBeanDefinitions登疗。bean是節(jié)點(diǎn)才是我創(chuàng)建bean的解析過(guò)程排截。其中bean分支左后進(jìn)入到DefaultBeanDefinitionDocumentReader.processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 在BeanDefinitionParserDelegate中完成bean的解析,結(jié)果返回到BeanDefinitionHolder中
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
// BeanDefinitionParserDelegate在對(duì)holder進(jìn)行修飾(解析自定義的屬性)
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
// 向Ioc真正注冊(cè)裝飾之后的BeanDefinition實(shí)例
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
// BeanDefinition注冊(cè)完成之后發(fā)送消息
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
1.2.3 BeanDefinition在IoC容器的注冊(cè)
bean的注冊(cè)過(guò)程辐益,從上面解析過(guò)程完成之后断傲,就開(kāi)始注冊(cè)了,上面帶出顯示
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
進(jìn)入BeanDefinitionReaderUtils智政,registerBeanDefinition方法中最后調(diào)用BeanDefinitionRegistry接口的registerBeanDefinition认罩。查看DefaultListableBeanFactory中的實(shí)現(xiàn)
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
// 校驗(yàn)BeanDefinition
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
// private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);
// key是beanName,value是BeanDefinition
synchronized (this.beanDefinitionMap) {
BeanDefinition oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
// 如果同名的bean已經(jīng)注冊(cè),但是設(shè)置allowBeanDefinitionOverriding為false(即不允許定義重復(fù)),則拋出異常
// 默認(rèn)的allowBeanDefinitionOverriding為true
// 網(wǎng)上看到的設(shè)置allowBeanDefinitionOverriding的方法,但此方法有點(diǎn)局限在web項(xiàng)目中续捂,方案鏈接如下:
// http://blog.csdn.net/zgmzyr/article/details/39380477
// 那么還有沒(méi)有更好的辦法呢 垦垂?
if (!this.allowBeanDefinitionOverriding) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
// 如果設(shè)置允許不定義不一致,但是重復(fù)的情況下牙瓢,判斷BeanDefition的role級(jí)別,日志提醒
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
" with a framework-generated bean definition ': replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
else {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
}
else {
// 如果沒(méi)有重復(fù),添加beanName到list中四瘫,按照注冊(cè)順序排序
this.beanDefinitionNames.add(beanName);
this.frozenBeanDefinitionNames = null;
}
// 添加BeanDefinition到map中
this.beanDefinitionMap.put(beanName, beanDefinition);
}
resetBeanDefinition(beanName);
}
回答上面提到的問(wèn)題稳析,如果設(shè)置allowBeanDefinitionOverriding還有什么方法诚纸,那就是使用IoC的釋放畦徘,方法換掉
@Test
public void testProgramWayIoC() {
// 確定資源
Resource res = new ClassPathResource("application.xml");
// 創(chuàng)建一個(gè)BeanFactory,設(shè)置部分不想使用默認(rèn)值的屬性
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
factory.setAllowBeanDefinitionOverriding(false);
// 創(chuàng)建BeanDefinitionReader
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
// 加載DeanDefinition并向IoC容器注冊(cè)
reader.loadBeanDefinitions(res);
// 使用bean
TestBean test = factory.getBean("testBean",TestBean.class);
test.testMethod();
}
雖然這樣可以,但是相比較來(lái)講,代碼注釋的地方提到的方案萍肆,相對(duì)更加實(shí)用。這里說(shuō)明這個(gè)只是說(shuō)可以用編程的方式使用IoC容器馏艾。
1.3 IoC的依賴注入
依賴注入的地方是在第一次使用getBean的時(shí)候注入的铁孵。但是當(dāng)設(shè)置了lazy-init的時(shí)候會(huì)在BeadDefinition載入的時(shí)候注入。
getBean是BeanFactory接口提供的方法岖沛,其實(shí)現(xiàn)在AbstractBeanFactory中
另外:ListableBeanFactory中有一個(gè)<T> T getBean(Class<T> requiredType) throws BeansException;
的接口廊镜,在DefaultListableBeanFactory
中實(shí)現(xiàn)。
依賴注入過(guò)程
AbstractBeanFactory.doCreateBean()-->AbstractBeanFactory.createBean()-->AbstractAutowireCapableBeanFactory.createBean()-->AbstractAutowireCapableBeanFactory.doCreateBean()-->AbstractAutowireCapableBeanFactory.createBeanInstance()-->initializeBean()-->registerDisposableBeanIfNecessary
1.4 前后處理器與容器的感知
1.4.1 BeanPostProcessor 與 BeanFactoryPostProcessor
BeanFactoryPostProcessor
是BeanFactory的后置處理器
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
他只在beanFactory創(chuàng)建完成時(shí)候調(diào)用過(guò)一次,可以得到一個(gè)BeanFactory的子類吱雏。操作BeanFactory
BeanPostProcessor
是Bean的前后置處理器,可以在bean的初始化前后操作得滤。可是獲得beanName,修改Bean
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
這里面的兩個(gè)方法在所有的bean的初始化過(guò)程中都會(huì)調(diào)用,可以理解為一個(gè)攔截去的樣子慷暂。
InitializingBean
接口,主要實(shí)在bean實(shí)例化之后設(shè)置屬性血久,即各種感知器執(zhí)行完成之后
1.4.2 感知(Aware)
有些時(shí)候需要在bean使用IoC容器,對(duì)IoC容器進(jìn)行操作,這個(gè)時(shí)候就可以利用感知器的特點(diǎn)得到IoC進(jìn)行操作角骤。
幾種常用的感知器:
- BeanNameAware, 可以在Bean中得到它在IoC容器中的實(shí)例名稱
- BeanFactoryAware, 可以在Bean中得到bean所在的容器(beanFactory對(duì)象)优烧,從而在bean中直接使用IoC容器的服務(wù)又沾。
- ApplicationContextAware, 可以在bean中得到bean所在應(yīng)用的上下文,從而直接在Bean中使用上下文的服務(wù)。例如利用上下文getBean
- MessageSourceAware, 在Bean中得到消息源
- ApplicationEventPublisherAware,在Bean中得到上下文事件發(fā)布器,從而可以在Bean中發(fā)布應(yīng)用上下文事件
- ResourceLoaderAware, 在Bean中得到ResourceLoader,從而在bean中使用ResourceLoader加載外部對(duì)應(yīng)的Resource資源
1.5 Bean生命周期
bean的生命周期艾扮,整個(gè)過(guò)程就是先執(zhí)行BeanFactory的創(chuàng)建呛梆,如果有就不用再創(chuàng)建锐涯,在執(zhí)行beanFactory的后置處理器磕诊,再執(zhí)行實(shí)例化感知器。接下實(shí)例化。注入屬性霎终。調(diào)用各種Bean的感知器滞磺。調(diào)用bean的前后置處理器。如下圖:
圖片來(lái)源:http://www.cnblogs.com/zrtqsk/p/3735273.html