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