关于spring:spring源码解析springcore二

7次阅读

共计 28431 个字符,预计需要花费 72 分钟才能阅读完成。

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

高深莫测。

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

正文完
 0