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中的主要数据结构以下图:
此方法负责对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:
<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寻找。
此方法容许子类在全部的bean还没有初始化以前注册BeanPostProcessor。空实现且没有子类覆盖。
BeanFactoryPostProcessor接口容许咱们在bean正是初始化以前改变其值。此接口只有一个方法:
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory);
有两种方式能够向Spring添加此对象:
context.addBeanFactoryPostProcessor
<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事件驱动模型
这又是一个模版方法,容许子类在进行bean初始化以前进行一些定制操做。默认空实现。
registerListeners方法干的,没什么好说的
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),转载请注明出处。