spring源碼解析---spring-core(二)

Bean解析html

XmlBeanDefinitionReader.registerBeanDefinitions:java

public int registerBeanDefinitions(Document doc, Resource resource) {node

    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();spring

    int countBefore = getRegistry().getBeanDefinitionCount();數組

    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));緩存

    return getRegistry().getBeanDefinitionCount() - countBefore;數據結構

}app

createBeanDefinitionDocumentReader:dom

protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {異步

return BeanDefinitionDocumentReader.class.cast

//反射

(BeanUtils.instantiateClass(this.documentReaderClass));

}

documentReaderClass默認是DefaultBeanDefinitionDocumentReader,這其實也是策略模式,經過setter方法能夠更換其實現。

注意cast方法代替了強轉。

createReaderContext

public XmlReaderContext createReaderContext(Resource resource) {

    return new XmlReaderContext(resource, this.problemReporter, this.eventListener,

    this.sourceExtractor, this, getNamespaceHandlerResolver());

}

problemReporter是一個FailFastProblemReporter對象。

eventListener是EmptyReaderEventListener對象,此類裏的方法都是空實現。

sourceExtractor是NullSourceExtractor對象,直接返回空,也是空實現。

getNamespaceHandlerResolver默認返回DefaultNamespaceHandlerResolver對象,用來獲取xsd對應的處理器。

XmlReaderContext的做用感受就是這一堆參數的容器,糅合到一塊兒傳給DocumentReader,並美其名爲Context。能夠看出,Spring中處處都是策略模式,大量操做被抽象成接口。

DefaultBeanDefinitionDocumentReader.registerBeanDefinitions:

@Overridepublic void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {

    this.readerContext = readerContext;

    Element root = doc.getDocumentElement();

    doRegisterBeanDefinitions(root);

}

doRegisterBeanDefinitions:

protected void doRegisterBeanDefinitions(Element root) {

BeanDefinitionParserDelegate parent = this.delegate;

this.delegate = createDelegate(getReaderContext(), root, parent);

//默認的命名空間即

//http://www.springframework.org/schema/beans

if (this.delegate.isDefaultNamespace(root)) {

//檢查profile屬性

String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);

if (StringUtils.hasText(profileSpec)) {

//profile屬性能夠以,分割

String[] specifiedProfiles = StringUtils.tokenizeToStringArray(

profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);

if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {

return;

}

}

}

preProcessXml(root);

parseBeanDefinitions(root, this.delegate);

postProcessXml(root);

this.delegate = parent;

}

delegate的做用在於處理beans標籤的嵌套,其實Spring配置文件是能夠寫成這樣的:

<?xml version="1.0" encoding="UTF-8"?>

<beans>

<bean class="base.SimpleBean"></bean>

<beans>

<bean class="java.lang.Object"></bean>

</beans>

</beans>

從圖中能夠大約猜出 這個處理xml中的Elements/beans標籤的嵌套

xml(schema)的命名空間其實相似於java的報名,命名空間採用URL,好比Spring的是這樣:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"></beans>

xmlns屬性就是xml規範定義的用來設置命名空間的。這樣設置了以後其實裏面的bean元素全名就至關於http://www.springframework.org/schema/beans:bean,能夠有效的防止命名衝突。命名空間能夠經過規範定義的org.w3c.dom.Node.getNamespaceURI方法得到。

注意一下profile的檢查, AbstractEnvironment.acceptsProfiles:

@Overridepublic boolean acceptsProfiles(String... profiles) {

Assert.notEmpty(profiles, "Must specify at least one profile");

for (String profile : profiles) {

if (StringUtils.hasLength(profile) && profile.charAt(0) == '!') {

if (!isProfileActive(profile.substring(1))) {

return true;

}

} else if (isProfileActive(profile)) {

return true;

}

}

return false;

}

原理很簡單,注意從源碼能夠看出,profile屬性支持!取反

preProcessXml方法是個空實現,供子類去覆蓋,目的在於給子類一個把咱們自定義的標籤轉爲Spring標準標籤的機會, 想的真周到。

DefaultBeanDefinitionDocumentReader.parseBeanDefinitions:

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {

if (delegate.isDefaultNamespace(root)) {

NodeList nl = root.getChildNodes();

for (int i = 0; i < nl.getLength(); i++) {

Node node = nl.item(i);

if (node instanceof Element) {

Element ele = (Element) node;

if (delegate.isDefaultNamespace(ele)) {

parseDefaultElement(ele, delegate);

} else {

delegate.parseCustomElement(ele);

}

}

}

} else {

delegate.parseCustomElement(root);

}

}

可見,對於非默認命名空間的元素交由delegate處理。

默認命名空間解析

即import, alias, bean, 嵌套的beans四種元素。parseDefaultElement:

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {

//"import"

if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {

importBeanDefinitionResource(ele);

}

//"alias"

else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {

processAliasRegistration(ele);

}

//"bean"

else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {

processBeanDefinition(ele, delegate);

}

//"beans"

else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {

// recurse

doRegisterBeanDefinitions(ele);

}

}

import

寫法示例:

<import resource="CTIContext.xml" />

<import resource="customerContext.xml" />

importBeanDefinitionResource套路和以前的配置文件加載徹底同樣,不過注意被import進來的文件是先於當前文件 被解析的。

alias

加入有一個bean名爲componentA-dataSource,可是另外一個組件想以componentB-dataSource的名字使用,就能夠這樣定義:

<alias name="componentA-dataSource" alias="componentB-dataSource"/>

processAliasRegistration核心源碼:

protected void processAliasRegistration(Element ele) {

String name = ele.getAttribute(NAME_ATTRIBUTE);//NAME_ATTRIBUTE=="name"

String alias = ele.getAttribute(ALIAS_ATTRIBUTE);//ALIAS_ATTRIBUTE ="alias"

getReaderContext().getRegistry().registerAlias(name, alias);

getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));

}

4.2.2的部分代碼

從前面的源碼能夠發現,registry其實就是DefaultListableBeanFactory,它實現了BeanDefinitionRegistry接口(這裏我用上面的圖片證明 更確信)。registerAlias方法的實如今_SimpleAliasRegistry_:

@Overridepublic void registerAlias(String name, String alias) {

Assert.hasText(name, "'name' must not be empty");

Assert.hasText(alias, "'alias' must not be empty");

//名字和別名同樣

if (alias.equals(name)) {

//ConcurrentHashMap

this.aliasMap.remove(alias);

} else {

String registeredName = this.aliasMap.get(alias);

if (registeredName != null) {

if (registeredName.equals(name)) {

// An existing alias - no need to re-register

return;

}

if (!allowAliasOverriding()) {

throw new IllegalStateException

("Cannot register alias '" + alias + "' for name '" +

name + "': It is already registered for name '" + registeredName + "'.");

}

}

checkForAliasCircle(name, alias);

this.aliasMap.put(alias, name);

}

}

因此別名關係的保存使用Map完成,key爲別名,value爲原本的名字。

bean

bean節點是Spring最最多見的節點了。

DefaultBeanDefinitionDocumentReader.processBeanDefinition:

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {

    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);

if (bdHolder != null) {

    bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

try {

// Register the final decorated instance.

    BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

}catch (BeanDefinitionStoreException ex) {

    getReaderContext().error("Failed to register bean definition with name '" +

    bdHolder.getBeanName() + "'", ele, ex);

}

    // Send registration event.

    getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));

}

}

id & name處理

最終調用BeanDefinitionParserDelegate.parseBeanDefinitionElement(Element ele, BeanDefinition containingBean),源碼較長,分部分說明。

首先獲取到id和name屬性,name屬性支持配置多個,以逗號(或分號)分隔,若是沒有指定id,那麼將以第一個name屬性值代替。id必須是惟一的,name屬性實際上是alias的角色,能夠和其它的bean重複,若是name也沒有配置,那麼其實什麼也沒作。(如圖所示把重點指出了)

beanName生成

若是name和id屬性都沒有指定,那麼Spring會本身生成一個, BeanDefinitionParserDelegate.parseBeanDefinitionElement:

beanName = this.readerContext.generateBeanName(beanDefinition);

String beanClassName = beanDefinition.getBeanClassName();

aliases.add(beanClassName);//generateBeanName最終調用的方法

4.2.2版本以下,稍微有些區別,就是這個生成的beanName是BeanDefinitionReaderUtils的工具類生成的,兩個版本最終調用的都仍是BeanDefinitionReaderUtils.generateBeanName:

可見,Spring同時會把類名做爲其別名。

最終調用的是BeanDefinitionReaderUtils.generateBeanName:

public static String generateBeanName(

BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean) {

String generatedBeanName = definition.getBeanClassName();

if (generatedBeanName == null) {

if (definition.getParentName() != null) {

generatedBeanName = definition.getParentName() + "$child";

//工廠方法產生的bean

} else if (definition.getFactoryBeanName() != null) {

generatedBeanName = definition.getFactoryBeanName() + "$created";

}

}

String id = generatedBeanName;

if (isInnerBean) {

// Inner bean: generate identity hashcode suffix.

id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR +

ObjectUtils.getIdentityHexString(definition);

} else {

// Top-level bean: use plain class name.

// Increase counter until the id is unique.

int counter = -1;

//用類名#自增的數字命名

while (counter == -1 || registry.containsBeanDefinition(id)) {

counter++;

id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + counter;

}

}

return id;

}

bean解析

仍是分部分說明(parseBeanDefinitionElement)。

首先獲取到bean的class屬性和parent屬性,配置了parent以後,當前bean會繼承父bean的屬性。以後根據class和parent建立BeanDefinition對象。

String className = null;

if (ele.hasAttribute(CLASS_ATTRIBUTE)) {

    className = ele.getAttribute(CLASS_ATTRIBUTE).trim();

}

String parent = null;

if (ele.hasAttribute(PARENT_ATTRIBUTE)) {

    parent = ele.getAttribute(PARENT_ATTRIBUTE);

}

AbstractBeanDefinition bd = createBeanDefinition(className, parent);

BeanDefinition的建立在BeanDefinitionReaderUtils.createBeanDefinition:

public static AbstractBeanDefinition createBeanDefinition(

        String parentName, String className, ClassLoader classLoader) {

    GenericBeanDefinition bd = new GenericBeanDefinition();

    bd.setParentName(parentName);

    if (className != null) {

        if (classLoader != null) {

            bd.setBeanClass(ClassUtils.forName(className, classLoader));

        }

        else {

            bd.setBeanClassName(className);

        }

    }

    return bd;

}

BeanDefinition的建立在BeanDefinitionReaderUtils.createBeanDefinition:

public static AbstractBeanDefinition createBeanDefinition(

    String parentName, String className, ClassLoader classLoader) {

    GenericBeanDefinition bd = new GenericBeanDefinition();

    bd.setParentName(parentName);

if (className != null) {

    if (classLoader != null) {

    bd.setBeanClass(ClassUtils.forName(className, classLoader));

}else {

    bd.setBeanClassName(className);

    }

}

    return bd;

}

以後是解析bean的其它屬性,其實就是讀取其配置,調用相應的setter方法保存在BeanDefinition中:

parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);

以後解析bean的decription子元素:

<bean id="b" name="one, two" class="base.SimpleBean">

<description>SimpleBean</description>

</bean>

就僅僅是個描述。

而後是meta子元素的解析,meta元素在xml配置文件裏是這樣的:

<bean id="b" name="one, two" class="base.SimpleBean">

<meta key="name" value="skywalker"/>

</bean>

註釋上說,這樣能夠將任意的元數據附到對應的bean definition上。解析過程源碼:

public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {

    NodeList nl = ele.getChildNodes();

    for (int i = 0; i < nl.getLength(); i++) {

    Node node = nl.item(i);

    if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) {

        Element metaElement = (Element) node;

        String key = metaElement.getAttribute(KEY_ATTRIBUTE);

        String value = metaElement.getAttribute(VALUE_ATTRIBUTE);

        //就是一個key, value的載體,無他

        BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);

        //sourceExtractor默認是NullSourceExtractor,返回的是空

        attribute.setSource(extractSource(metaElement));

        attributeAccessor.addMetadataAttribute(attribute);

        }

    }

}

AbstractBeanDefinition繼承自BeanMetadataAttributeAccessor類,底層使用了一個LinkedHashMap保存metadata。這個metadata具體是作什麼暫時還不知道。

lookup-method解析:

此標籤的做用在於當一個bean的某個方法被設置爲lookup-method後,每次調用此方法時,都會返回一個新的指定bean的對象。用法示例:

<bean id="apple" class="cn.com.willchen.test.di.Apple" scope="prototype"/>

<!--水果盤-->

<bean id="fruitPlate" class="cn.com.willchen.test.di.FruitPlate">

<lookup-method name="getFruit" bean="apple"/>

</bean>

數據保存在Set中,對應的類是MethodOverrides。能夠參考:

Spring - lookup-method方式實現依賴注入

replace-mothod解析:

此標籤用於替換bean裏面的特定的方法實現,替換者必須實現Spring的MethodReplacer接口,有點像aop的意思。

配置文件示例:

<bean name="replacer" class="springroad.deomo.chap4.MethodReplace" />

<bean name="testBean" class="springroad.deomo.chap4.LookupMethodBean">

<replaced-method name="test" replacer="replacer">

<arg-type match="String" />

</replaced-method>

</bean>

arg-type的做用是指定替換方法的參數類型,由於接口的定義參數都是Object的。參考: SPRING.NET 1.3.2 學習20--方法注入之替換方法注入

解析以後將數據放在ReplaceOverride對象中,裏面有一個LinkedList專門用於保存arg-type。

構造參數(constructor-arg)解析:

做用一目瞭然,使用示例:

<bean class="base.SimpleBean">

<constructor-arg>

<value type="java.lang.String">Cat</value>

</constructor-arg>

</bean>

type通常不須要指定,除了泛型集合那種。除此以外,constructor-arg還支持name, index, ref等屬性,能夠具體的指定參數的位置等。構造參數解析後保存在BeanDefinition內部一個ConstructorArgumentValues對象中。若是設置了index屬性,那麼以Map<Integer, ValueHolder>的形式保存,反之,以List的形式保存。

property解析:

很是經常使用的標籤,用覺得bean的屬性賦值,支持value和ref兩種形式,示例:

<bean class="base.SimpleBean">

<property name="name" value="skywalker" />

</bean>

value和ref屬性不能同時出現,若是是ref,那麼將其值保存在不可變的RuntimeBeanReference對象中,其實現了BeanReference接口,此接口只有一個getBeanName方法。若是是value,那麼將其值保存在TypedStringValue對象中。最終將對象保存在BeanDefinition內部一個MutablePropertyValues對象中(內部以ArrayList實現)。

qualifier解析:

配置示例:

<bean class="base.Student">

<property name="name" value="skywalker"></property>

<property name="age" value="12"></property>

<qualifier type="org.springframework.beans.factory.annotation.Qualifier" value="student" />

</bean>

<bean class="base.Student">

<property name="name" value="seaswalker"></property>

<property name="age" value="15"></property>

<qualifier value="student_2"></qualifier>

</bean>

<bean class="base.SimpleBean" />

SimpleBean部分源碼:

@Autowired

@Qualifier("student")

private Student student;

此標籤和@Qualifier, @Autowired兩個註解一塊兒使用纔有做用。@Autowired註解採用按類型查找的方式進行注入,若是找到多個須要類型的bean便會報錯,有了@Qualifier標籤就能夠再按照此註解指定的名稱查找。二者結合至關於實現了按類型+名稱注入。type屬性能夠不指定,由於默認就是那個。qualifier標籤能夠有attribute子元素,好比:

<qualifier type="org.springframework.beans.factory.annotation.Qualifier" value="student">

<attribute key="id" value="1"/>

</qualifier>

貌似是用來在qualifier也區分不開的時候使用。attribute鍵值對保存在BeanMetadataAttribute對象中。整個qualifier保存在AutowireCandidateQualifier對象中。

Bean裝飾

這部分是針對其它schema的屬性以及子節點,好比:

<bean class="base.Student" primary="true">

<context:property-override />

</bean>

沒見過這種用法,留個坑。

Bean註冊

BeanDefinitionReaderUtils.registerBeanDefinition:

public static void registerBeanDefinition(

BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {

// Register bean definition under primary name.

String beanName = definitionHolder.getBeanName();

registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

// Register aliases for bean name, if any.

String[] aliases = definitionHolder.getAliases();

if (aliases != null) {

for (String alias : aliases) {

registry.registerAlias(beanName, alias);

}

}

}

registry其實就是DefaultListableBeanFactory對象,registerBeanDefinition方法主要就幹了這麼兩件事:

@Overridepublic void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {

this.beanDefinitionMap.put(beanName, beanDefinition);

this.beanDefinitionNames.add(beanName);

}

一個是Map,另外一個是List,一目瞭然。registerAlias方法的實如今其父類SimpleAliasRegistry,就是把鍵值對放在了一個ConcurrentHashMap裏。

ComponentRegistered事件觸發:

默認是個空實現,前面說過了。

BeanDefinition數據結構(做者此處寫成了BeanDefiniton 差之毫釐謬以千里 怪不得找不到這個類)

BeanDefinition數據結構以下圖:

beans

beans元素的嵌套直接遞歸調用DefaultBeanDefinitionDocumentReader.parseBeanDefinitions。

其它命名空間解析

入口在DefaultBeanDefinitionDocumentReader.parseBeanDefinitions->BeanDefinitionParserDelegate.parseCustomElement(第二個參數爲空):

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {

String namespaceUri = getNamespaceURI(ele);

NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);

return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));

}

NamespaceHandlerResolver由XmlBeanDefinitionReader初始化,是一個DefaultNamespaceHandlerResolver對象,也是NamespaceHandlerResolver接口的惟一實現。

其resolve方法:

@Overridepublic NamespaceHandler resolve(String namespaceUri) {

    Map<String, Object> handlerMappings = getHandlerMappings();

    Object handlerOrClassName = handlerMappings.get(namespaceUri);

if (handlerOrClassName == null) {

    return null;

} else if (handlerOrClassName instanceof NamespaceHandler) {

    return (NamespaceHandler) handlerOrClassName;

} else {

    String className = (String) handlerOrClassName;

    Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);//之後能夠這樣用

    NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);

    namespaceHandler.init();

    handlerMappings.put(namespaceUri, namespaceHandler);

    return namespaceHandler;

    }

}

容易看出,Spring其實使用了一個Map了保存其映射關係,key就是命名空間的uri,value是NamespaceHandler對象或是Class完整名,若是發現是類名,那麼用反射的方法進行初始化,若是是NamespaceHandler對象,那麼直接返回

NamespaceHandler映射關係來自於各個Spring jar包下的META-INF/spring.handlers文件,以spring-context包爲例:

http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler

http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler

http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler

http\://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandler

http\://www.springframework.org/schema/cache=org.springframework.cache.config.CacheNamespaceHandler

NamespaceHandler繼承體系

init

resolve中調用了其init方法,此方法用以向NamespaceHandler對象註冊BeanDefinitionParser對象。此接口用以解析頂層(beans下)的非默認命名空間元素,好比<context:annotation-config />

因此這樣邏輯就很容易理解了: 每種子標籤的解析還是策略模式的體現,init負責向父類NamespaceHandlerSupport註冊不一樣的策略,由父類的NamespaceHandlerSupport.parse方法根據具體的子標籤調用相應的策略完成解析的過程

此部分較爲重要,因此從新開始大綱。

BeanFactory數據結構

BeanDefinition在BeanFactory中的主要數據結構以下圖:

prepareBeanFactory

此方法負責對BeanFactory進行一些特徵的設置工做,"特徵"包含這麼幾個方面:

BeanExpressionResolver

此接口只有一個實現: StandardBeanExpressionResolver。接口只含有一個方法:

Object evaluate(String value, BeanExpressionContext evalContext)

prepareBeanFactory將一個此對象放入BeanFactory:

beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));

StandardBeanExpressionResolver對象內部有一個關鍵的成員: SpelExpressionParser,其整個類圖:

這即是Spring3.0開始出現的Spel表達式的解釋器。

PropertyEditorRegistrar

此接口用於向Spring註冊java.beans.PropertyEditor,只有一個方法:

registerCustomEditors(PropertyEditorRegistry registry)

實現也只有一個: ResourceEditorRegistrar。

在編寫xml配置時,咱們設置的值都是字符串形式,因此在使用時確定須要轉爲咱們須要的類型,PropertyEditor接口正是定義了這麼個東西。

prepareBeanFactory:

beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));        

BeanFactory也暴露了registerCustomEditors方法用以添加自定義的轉換器,因此這個地方是組合模式的體現。

咱們有兩種方式能夠添加自定義PropertyEditor:

  • 經過context.getBeanFactory().registerCustomEditor
  • 經過Spring配置文件:

    <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">

    <property name="customEditors">

    <map>

    <entry key="base.Cat" value="base.CatEditor" />

    </map>

    </property>

    </bean>

參考: 深刻理解JavaBean(2):屬性編輯器PropertyEditor

環境注入

其實下面的一切都是圍繞這個AbstractApplicationContext.prepareBeanFactory方法方法展開的。**

在Spring中咱們本身的bean能夠經過實現EnvironmentAware等一系列Aware接口獲取到Spring內部的一些對象。prepareBeanFactory:

beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));//

private void invokeAwareInterfaces(Object bean) {

    if (bean instanceof Aware) {

    if (bean instanceof EnvironmentAware) {

        ((EnvironmentAware)bean).setEnvironment(this.applicationContext.getEnvironment());

    }

    if (bean instanceof EmbeddedValueResolverAware) {

        ((EmbeddedValueResolverAware)bean).setEmbeddedValueResolver(new                          ApplicationContextAwareProcessor.EmbeddedValueResolver(this.applicationContext.getBeanFactory()));

    }

//....

}

此部分設置哪些接口在進行依賴注入的時候應該被忽略:

beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);

beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);

beanFactory.ignoreDependencyInterface(MessageSourceAware.class);

beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

beanFactory.ignoreDependencyInterface(EnvironmentAware.class);

bean假裝

有些對象並不在BeanFactory中,可是咱們依然想讓它們能夠被裝配,這就須要假裝一下:

beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);

beanFactory.registerResolvableDependency(ResourceLoader.class, this);

beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);

beanFactory.registerResolvableDependency(ApplicationContext.class, this);

假裝關係保存在一個Map<Class<?>, Object>裏。

LoadTimeWeaver

若是配置了此bean,那麼:

if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {  //添加後置處理器  實際就是「loadTimeWeaver」

    beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));

    // Set a temporary ClassLoader for type matching.

    beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));

}

這個東西具體是幹什麼的在後面context:load-time-weaver中說明。

註冊環境

源碼:

if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {//environment 可見下圖

    beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());

}

if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {

    beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());

}

if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {

    beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().

        getSystemEnvironment());

}

containsLocalBean特殊之處在於不會去父BeanFactory尋找。

postProcessBeanFactory

    此方法容許子類在全部的bean還沒有初始化以前註冊BeanPostProcessor。空實現且沒有子類覆蓋。

invokeBeanFactoryPostProcessors

    BeanFactoryPostProcessor接口容許咱們在bean正是初始化以前改變其值。此接口只有一個方法:

void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory);

有兩種方式能夠向Spring添加此對象:

  • 經過代碼的方式:

    context.addBeanFactoryPostProcessor

  • 經過xml配置的方式:

    <bean class="base.SimpleBeanFactoryPostProcessor" />

注意此時還沒有進行bean的初始化工做,初始化是在後面的finishBeanFactoryInitialization進行的,因此在BeanFactoryPostProcessor對象中獲取bean會致使提早初始化。

此方法的關鍵源碼:

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {

PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory,

getBeanFactoryPostProcessors());

}

getBeanFactoryPostProcessors獲取的就是AbstractApplicationContext的成員beanFactoryPostProcessors(ArrayList),可是頗有意思,只有經過context.addBeanFactoryPostProcessor這種方式添加的纔會出如今這個List裏,因此對於xml配置方式,此List其實沒有任何元素。玄機就在PostProcessorRegistrationDelegate裏

核心思想就是使用BeanFactory的getBeanNamesForType方法獲取相應的BeanDefinition的name數組,以後逐一調用getBean方法獲取到bean(初始化),getBean方法後面再說。

注意此處有一個優先級的概念,若是你的BeanFactoryPostProcessor同時實現了Ordered或者是PriorityOrdered接口,那麼會被首先執行。

BeanPostProcessor註冊

此部分實質上是在BeanDefinitions中尋找BeanPostProcessor,以後調用BeanFactory.addBeanPostProcessor方法保存在一個List中,注意添加時仍然有優先級的概念,優先級高的在前面。

(AbstractApplicationContext.refresh裏面的方法  initMessageSource;初始化MessageSource)

MessageSource

此接口用以支持Spring國際化。繼承體系以下:

AbstractApplicationContext的initMessageSource()方法就是在BeanFactory中查找MessageSource的bean,若是配置了此bean,那麼調用getBean方法完成其初始化並將其保存在AbstractApplicationContext內部messageSource成員變量中,用以處理ApplicationContext的getMessage調用,由於從繼承體系上來看,ApplicationContext是MessageSource的子類,此處是委託模式的體現。若是沒有配置此bean,那麼初始化一個DelegatingMessageSource對象,此類是一個空實現,一樣用以處理getMessage調用請求。

參考: 學習Spring必學的Java基礎知識(8)----國際化信息

事件驅動

4.1.1版本源碼

protected void initApplicationEventMulticaster() {

    ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();

    if (beanFactory.containsLocalBean("applicationEventMulticaster")) {

        this.applicationEventMulticaster = (ApplicationEventMulticaster)beanFactory.getBean("applicationEventMulticaster", ApplicationEventMulticaster.class);

    if (this.logger.isDebugEnabled()) {

        this.logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");

    }

} else {

    this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);

    beanFactory.registerSingleton("applicationEventMulticaster", this.applicationEventMulticaster);

    if (this.logger.isDebugEnabled()) {

        this.logger.debug("Unable to locate ApplicationEventMulticaster with name 'applicationEventMulticaster': using default [" + this.applicationEventMulticaster + "]");

    }

}

}

此接口表明了Spring的事件驅動(監聽器)模式。一個事件驅動包含三部分:

事件

java的全部事件對象通常都是java.util.EventObject的子類,Spring的整個繼承體系以下:

發佈者

ApplicationEventPublisher(可見上圖)

一目瞭然。

ApplicationEventMulticaster

ApplicationEventPublisher實際上正是將請求委託給ApplicationEventMulticaster來實現的。其繼承體系:

監聽器

全部的監聽器是jdk EventListener的子類,這是一個mark接口。繼承體系:

事件發佈

AbstractApplicationContext.publishEvent核心代碼:

protected void publishEvent(Object event, ResolvableType eventType) {

getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);

}

SimpleApplicationEventMulticaster.multicastEvent:

@Overridepublic void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {

ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));

for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {

    Executor executor = getTaskExecutor();

if (executor != null) {

    executor.execute(new Runnable() {

    @Override

    public void run() {

        invokeListener(listener, event);

    }

    });

  } else {

    invokeListener(listener, event);

        }

    }

}

監聽器獲取

獲取固然仍是經過beanFactory的getBean來完成的,值得注意的是Spring在此處使用了緩存(ConcurrentHashMap)來加速查找的過程。

同步/異步

能夠看出,若是executor不爲空,那麼監聽器的執行其實是異步的。那麼如何配置同步/異步呢?

全局

<task:executor id="multicasterExecutor" pool-size="3"/>

<bean class="org.springframework.context.event.SimpleApplicationEventMulticaster">

<property name="taskExecutor" ref="multicasterExecutor"></property>

</bean>

task schema是Spring從3.0開始加入的,使咱們能夠再也不依賴於Quartz實現定時任務,源碼在org.springframework.core.task包下,使用須要引入schema:

xmlns:task="http://www.springframework.org/schema/task"

xsi:schemaLocation="http://www.springframework.org/schema/taskhttp://www.springframework.or...d"

能夠參考: Spring定時任務的幾種實現

註解

開啓註解支持:

<!-- 開啓@AspectJ AOP代理 -->

<aop:aspectj-autoproxy proxy-target-class="true"/>

<!-- 任務調度器 -->

<task:scheduler id="scheduler" pool-size="10"/>

<!-- 任務執行器 -->

<task:executor id="executor" pool-size="10"/>

<!--開啓註解調度支持 @Async @Scheduled-->

<task:annotation-driven executor="executor" scheduler="scheduler" proxy-target-class="true"/>

在代碼中使用示例:

@Component

public class EmailRegisterListener implements ApplicationListener<RegisterEvent> {

@Async

@Override

public void onApplicationEvent(final RegisterEvent event) {

System.out.println("註冊成功,發送確認郵件給:" + ((User)event.getSource()).getUsername());

}

}

參考: 詳解Spring事件驅動模型

onRefresh

這又是一個模版方法,容許子類在進行bean初始化以前進行一些定製操做。默認空實現。

ApplicationListener註冊

registerListeners方法乾的,沒什麼好說的

singleton初始化

finishBeanFactoryInitialization:

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {

if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&

beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {

beanFactory.setConversionService(

beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));

}

if (!beanFactory.hasEmbeddedValueResolver()) {

beanFactory.addEmbeddedValueResolver(new StringValueResolver() {

@Override

public String resolveStringValue(String strVal) {

return getEnvironment().resolvePlaceholders(strVal);

}

});

}

String[] weaverAwareNames = beanFactory.getBeanNamesForType

(LoadTimeWeaverAware.class, false, false);

for (String weaverAwareName : weaverAwareNames) {

getBean(weaverAwareName);

}

// Allow for caching all bean definition metadata, not expecting further changes.

beanFactory.freezeConfiguration();

// Instantiate all remaining (non-lazy-init) singletons.

beanFactory.preInstantiateSingletons();

}

分部分說明。

ConversionService

此接口用於類型之間的轉換,在Spring裏其實就是把配置文件中的String轉爲其它類型,從3.0開始出現,目的和jdk的PropertyEditor接口是同樣的,參考ConfigurableBeanFactory.setConversionService註釋:

Specify a Spring 3.0 ConversionService to use for converting property values, as an alternative to JavaBeans PropertyEditors. @since 3.0

StringValueResolver

用於解析註解的值。接口只定義了一個方法:

String resolveStringValue(String strVal);

LoadTimeWeaverAware

實現了此接口的bean能夠獲得LoadTimeWeaver,此處僅僅初始化。

初始化

DefaultListableBeanFactory.preInstantiateSingletons:

@Overridepublic void preInstantiateSingletons() throws BeansException {

List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);

for (String beanName : beanNames) {

RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);

if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {

if (isFactoryBean(beanName)) {

final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX

+ beanName);

boolean isEagerInit;

if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {

isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {

@Override

public Boolean run() {

return ((SmartFactoryBean<?>) factory).isEagerInit();

}

}, getAccessControlContext());

}

else {

isEagerInit = (factory instanceof SmartFactoryBean &&

((SmartFactoryBean<?>) factory).isEagerInit());

}

if (isEagerInit) {

getBean(beanName);

}

}

else {

getBean(beanName);

}

}

}

// Trigger post-initialization callback for all applicable beans...

for (String beanName : beanNames) {

Object singletonInstance = getSingleton(beanName);

if (singletonInstance instanceof SmartInitializingSingleton) {

    final SmartInitializingSingleton smartSingleton =

    (SmartInitializingSingleton) singletonInstance;

if (System.getSecurityManager() != null) {

    AccessController.doPrivileged(new PrivilegedAction<Object>() {

    @Override

    public Object run() {

        smartSingleton.afterSingletonsInstantiated();

        return null;

        }

    }, getAccessControlContext());

}

else {

    smartSingleton.afterSingletonsInstantiated();

         }

        }

    }

}

首先進行Singleton的初始化,其中若是bean是FactoryBean類型(注意,只定義了factory-method屬性的普通bean並非FactoryBean),而且仍是SmartFactoryBean類型,那麼須要判斷是否須要eagerInit(isEagerInit是此接口定義的方法)。

本文來源於:宋文超super,專屬平臺有csdn、思否(SegmentFault)、 簡書、 開源中國(oschina),轉載請註明出處。
相關文章
相關標籤/搜索