转载

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

Bean解析

XmlBeanDefinitionReader.registerBeanDefinitions:

public int registerBeanDefinitions(Document doc, Resource resource) {

BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader ();

int countBefore = getRegistry().getBeanDefinitionCount();

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

return getRegistry().getBeanDefinitionCount() - countBefore;

}

createBeanDefinitionDocumentReader:

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(可见上图)

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

一目了然。

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/task http://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),转载请注明出处。

原文  https://segmentfault.com/a/1190000023375396
正文到此结束
Loading...