spring ioc初始化,从ApplicationContext出发,ApplicationContext的主要实现类是ClassPathXmlApplicationContext和FileSystemXmlApplicationContext,前者默认从类路径加载配置文件,后者默认从文件系统中装载配置文件。
ClassPathXmlApplicationContext有多个构造方法,我们最常用的就是通过传入字符串的构造方法。
ClassPathXmlApplicationContext 构造方法
查看该构造方法:
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
初始化的核心就是在这个refresh(),进入该方法,是直接跳转到了AbstractApplicationContext中的refresh()方法中,说明子类并没有重写,直接使用父类方法,在这个方法中完成了IOC容器的创建以及初始化工作。
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
// STEP 1: 刷新预处理
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// STEP 2:
// a) 创建IoC容器(DefaultListableBeanFactory)
// b) 加载解析XML文件(最终存储到Document对象中)
// c) 读取Document对象,并完成BeanDefinition的加载和注册工作
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// STEP 3: 对IoC容器进行一些预处理(设置一些公共属性)
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// STEP 4:
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// STEP 5: 调用BeanFactoryPostProcessor后置处理器对BeanDefinition处理
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// STEP 6: 注册BeanPostProcessor后置处理器
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// STEP 7: 初始化一些消息源(比如处理国际化的i18n等消息源)
initMessageSource();
// Initialize event multicaster for this context.
// STEP 8: 初始化应用事件广播器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// STEP 9: 初始化一些特殊的bean
onRefresh();
// Check for listener beans and register them.
// STEP 10: 注册一些监听器
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// STEP 11: 实例化剩余的单例bean(非懒加载方式)
// 注意事项:Bean的IoC、DI和AOP都是发生在此步骤
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// STEP 12: 完成刷新时,需要发布对应的事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
通过AbstractApplicationContext的obtainFreshBeanFactory()方法中的 refreshBeanFactory() 来完成IOC容器的
刷新。此方法是直接调用 AbstractRefreshableApplicationContext 中的重写方法
@Override
protected final void refreshBeanFactory() throws BeansException {
// 如果之前有IoC容器,则销毁
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 创建IoC容器,也就是DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
// 设置工厂的属性:是否允许BeanDefinition覆盖和是否允许循环依赖
customizeBeanFactory(beanFactory);
// 调用载入BeanDefinition的方法,在当前类中只定义了抽象的loadBeanDefinitions方法,具体的实现调用子类容器
loadBeanDefinitions(beanFactory);//钩子方法
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
该方法先判断是否有IOC容器,如果存在则销毁,并且关闭beanFactory.通过createBeanFactory()方法来返回一个DefaultListableBeanFactory,接下来通过loadBeanDefinitions(beanFactory)方法来装载。这个方法实际调用的是子类AbstractXmlApplicationContext中的loadBeanDefinitions方法,该方法通过创建一个BeanDefinition阅读器,通过阅读xml文件来加载和注册。给这个XmlBeanDefinitionReader对象赋上了一些初始值以后,再次通过调用重载的同名loadBeanDefinitions(XmlBeanDefinitionReader reader)方法。
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
// 获取资源的定位
// 这里getConfigResources是一个空实现,真正实现是调用子类的获取资源定位的方法
// 比如:ClassPathXmlApplicationContext中进行了实现
// 而FileSystemXmlApplicationContext没有使用该方法
Resource[] configResources = getConfigResources();
if (configResources != null) {
// XML Bean读取器调用其父类AbstractBeanDefinitionReader读取定位的资源
reader.loadBeanDefinitions(configResources);
}
// 如果子类中获取的资源定位为空,则获取FileSystemXmlApplicationContext构造方法中setConfigLocations方法设置的资源
String[] configLocations = getConfigLocations();
if (configLocations != null) {
// XML Bean读取器调用其父类AbstractBeanDefinitionReader读取定位的资源
reader.loadBeanDefinitions(configLocations);
}
}
XmlBean读取器(XmlBeanDefinitionReader)调用其父类AbstractBeanDefinitionReader的 reader.loadBeanDefinitions方法读取Bean定义资源。
AbstractBeanDefinitionReader读取Bean定义资源,在其抽象父类AbstractBeanDefinitionReader中定 义了载入过程。
AbstractBeanDefinitionReader的loadBeanDefinitions方法源码如下:
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources)
throws BeanDefinitionStoreException {
// 获取在IoC容器初始化过程中设置的资源加载器
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
}
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
// 委派调用其子类XmlBeanDefinitionReader的方法,实现加载功能
int loadCount = loadBeanDefinitions(resources);
if (actualResources != null) {
for (Resource resource : resources) {
actualResources.add(resource);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
}
return loadCount;
} catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex);
}
} else {
// Can only load single resources by absolute URL.
Resource resource = resourceLoader.getResource(location);
int loadCount = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
}
return loadCount;
}
}
通过传入参数location地址来获取资源resources,再将resources传入调用子类XmlBeanDefinitionReader的loadBeanDefinitions方法。
XmlBeanDefinitionReader的loadBeanDefinitions(EncodedResource encodedResource)方法如下:
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
// 将资源文件转为InputStream的IO流
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
// 从InputStream中得到XML的解析源
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
// 这里是具体的读取过程
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
这里将读入的xml通过特殊编码处理loadBeanDefinitions(new EncodedResource(resource)) (此处有使用到模板设计模式),通过doLoadBeanDefinitions方法来进行具体的读取过程。
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
// 通过DOM4J加载解析XML文件,最终形成Document对象
Document doc = doLoadDocument(inputSource, resource);
// 通过对Document对象的操作,完成BeanDefinition的加载和注册工作
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
这里面首先通过DOM4J加载解析XML文件,最终形成Document对象,再通过对Document对象的操作,完成BeanDefinition的加载和注册工作。
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// 创建BeanDefinitionDocumentReader来解析Document对象,完成BeanDefinition解析
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
// 获得容器中已经注册的BeanDefinition数量
int countBefore = getRegistry().getBeanDefinitionCount();
//解析过程入口,BeanDefinitionDocumentReader只是个接口,具体的实现过程在DefaultBeanDefinitionDocumentReader完成
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
// 统计新的的BeanDefinition数量
return getRegistry().getBeanDefinitionCount() - countBefore;
}
首先通过创建BeanDefinitionDocumentReader,再通过具体实现类DefaultBeanDefinitionDocumentReader的registerBeanDefinitions方法来进行真正的解析工作。
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
// 获得Document的根元素<beans>标签
Element root = doc.getDocumentElement();
// 真正实现BeanDefinition解析和注册工作
doRegisterBeanDefinitions(root);
}
DefaultBeanDefinitionDocumentReader的doRegisterBeanDefinitions(Element root)方法源码如下:
protected void doRegisterBeanDefinitions(Element root) {
// 这里使用了委托模式,将具体的BeanDefinition解析工作交给了BeanDefinitionParserDelegate去完成
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
// 判断该根标签是否包含http://www.springframework.org/schema/beans默认命名空间
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isInfoEnabled()) {
logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
// 在解析Bean定义之前,进行自定义的解析,增强解析过程的可扩展性
preProcessXml(root);
// 委托给BeanDefinitionParserDelegate,从Document的根元素开始进行BeanDefinition的解析
parseBeanDefinitions(root, this.delegate);
// 在解析Bean定义之后,进行自定义的解析,增加解析过程的可扩展性
postProcessXml(root);
this.delegate = parent;
}
parseBeanDefinitions方法将Document从根元素开始解析
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
// 加载的Document对象是否使用了Spring默认的XML命名空间(beans命名空间)
if (delegate.isDefaultNamespace(root)) {
// 获取Document对象根元素的所有子节点(bean标签、import标签、alias标签和其他自定义标签context、aop等)
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;
// bean标签、import标签、alias标签,则使用默认解析规则
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {//像context标签、aop标签、tx标签,则使用用户自定义的解析规则解析元素节点
delegate.parseCustomElement(ele);
}
}
}
}
else {
// 如果不是默认的命名空间,则使用用户自定义的解析规则解析元素节点
delegate.parseCustomElement(root);
}
}
通过委托判断是否是默认命名空间,如果是则使用parseDefaultElement方法解析默认元素(bean标签、import标签、alias标签和其他自定义标签context、aop等),如果不是默认命名空间,则通过parseCustomElement方法来解析用户自定义的元素节点(context标签、aop标签、tx标签)
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);
}
}
这里主要查看 processBeanDefinition如何解析bean标签:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 解析<bean>标签,获取BeanDefinition
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
// 如果需要,则装饰BeanDefinition对象
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
// 注册最终的BeanDefinition到BeanDefinitionRegistry(DefaultListableBeanFactory)
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));
}
}
这里先获取BeanDefinition,再通过BeanDefinitionReaderUtils.registerBeanDefinition方法来注册最终的BeanDefinition到BeanDefinitionRegistry(DefaultListableBeanFactory)。
解析bean标签,获取BeanDefinition的parseBeanDefinitionElement方法,是在BeanDefinitionParserDelegate中进行的:
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
// 获取bean的id
String id = ele.getAttribute(ID_ATTRIBUTE);
// 获取bean的name
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List<String> aliases = new ArrayList<>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isDebugEnabled()) {
logger.debug("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
if (containingBean == null) {
// 检查bean的id或者name是否唯一
checkNameUniqueness(beanName, aliases, ele);
}
// 解析<bean>标签,获取BeanDefinition对象
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
// Register an alias for the plain bean class name, if still possible,
// if the generator returned the class name plus a suffix.
// This is expected for Spring 1.2/2.0 backwards compatibility.
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Neither XML 'id' nor 'name' specified - " +
"using generated bean name [" + beanName + "]");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
// 将BeanDefinition对象和BeanName封装到BeanDefinitionHolder对象中
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
注意:在解析元素过程中没有创建和实例化Bean对象,只是创建了Bean对象的定义类BeanDefinition,将元素中的 配置信息设置到BeanDefinition中作为记录,当依赖注入时才使用这些记录信息创建和实例化具体的Bean对象。
parseBeanDefinitionElement具体源码如下:
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, @Nullable BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
String className = null;
// 获取bean标签的class属性
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
String parent = null;
// 获取bean标签的parent属性
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
try {
// 创建BeanDefinition对象GenericBeanDefinition
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
// 解析<bean>标签的属性
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
/** 解析<bean>标签的子标签 --- begin**/
// 解析<description>标签
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
// 解析<meta>标签
parseMetaElements(ele, bd);
// 解析<lookup-method>标签
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
// 解析<replaced-method>标签
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
// 解析<constructor-arg>标签
parseConstructorArgElements(ele, bd);
// 解析<property>标签
parsePropertyElements(ele, bd);
// 解析<qualifier>标签
parseQualifierElements(ele, bd);
/** 解析<bean>标签的子标签 --- end**/
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
}
catch (ClassNotFoundException ex) {
error("Bean class [" + className + "] not found", ele, ex);
}
catch (NoClassDefFoundError err) {
error("Class that bean class [" + className + "] depends on not found", ele, err);
}
catch (Throwable ex) {
error("Unexpected failure during bean definition parsing", ele, ex);
}
finally {
this.parseState.pop();
}
return null;
}
上面方法中一些对一些配置如元信息(meta)、qualifier等的解析,我们在Spring中配置时使用的也不多,我们在 使用Spring的元素时,配置最多的是属性,因此我们下面继续分析源码,了解Bean的属性在解析时是如何设置的。
parsePropertyElements方法解析元素中的属性子元素,解析源码如下:
/**
* property标签的解析
* Parse a property element.
*/
public void parsePropertyElement(Element ele, BeanDefinition bd) {
String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
if (!StringUtils.hasLength(propertyName)) {
error("Tag 'property' must have a 'name' attribute", ele);
return;
}
this.parseState.push(new PropertyEntry(propertyName));
try {
if (bd.getPropertyValues().contains(propertyName)) {
error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
return;
}
Object val = parsePropertyValue(ele, bd, propertyName);
PropertyValue pv = new PropertyValue(propertyName, val);
parseMetaElements(ele, pv);
pv.setSource(extractSource(ele));
bd.getPropertyValues().addPropertyValue(pv);
}
finally {
this.parseState.pop();
}
}
public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) {
String elementName = (propertyName != null) ?
"<property> element for property '" + propertyName + "'" :
"<constructor-arg> element";
// Should only have one child element: ref, value, list, etc.
NodeList nl = ele.getChildNodes();
Element subElement = null;
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
!nodeNameEquals(node, META_ELEMENT)) {
// Child element is what we're looking for.
if (subElement != null) {
error(elementName + " must not contain more than one sub-element", ele);
}
else {
subElement = (Element) node;
}
}
}
boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
if ((hasRefAttribute && hasValueAttribute) ||
((hasRefAttribute || hasValueAttribute) && subElement != null)) {
error(elementName +
" is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
}
if (hasRefAttribute) {
String refName = ele.getAttribute(REF_ATTRIBUTE);
if (!StringUtils.hasText(refName)) {
error(elementName + " contains empty 'ref' attribute", ele);
}
// 引用类型属性值信息
RuntimeBeanReference ref = new RuntimeBeanReference(refName);
ref.setSource(extractSource(ele));
return ref;
}
else if (hasValueAttribute) {
// 简单类型属性值信息
TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
valueHolder.setSource(extractSource(ele));
return valueHolder;
}
else if (subElement != null) {
return parsePropertySubElement(subElement, bd);
}
else {
// Neither child element nor "ref" or "value" attribute found.
error(elementName + " must specify a ref or value", ele);
return null;
}
}
通过对上述源码的分析,我们可以了解在Spring配置文件中,元素中元素的相关配置是如何处理的:
a.ref被封装为指向依赖对象一个引用。
b.value配置都会封装成一个字符串类型的对象。
c.ref和value都通过“解析的数据类型属性值.setSource(extractSource(ele));”方法将属性值/引用与所引用 的属性关联起来。
经过对SpringBean定义资源文件转换的Document对象中的元素层层解析,SpringIOC现在已经将XML形式定义的 Bean定义资源文件转换为SpringIOC所识别的数据结构——BeanDefinition,它是Bean定义资源文件中配置的 POJO对象在SpringIOC容器中的映射,我们可以通过AbstractBeanDefinition为入口,看到了IOC容器进行索引、 查询和操作。 通过SpringIOC容器对Bean定义资源的解析后,IOC容器大致完成了管理Bean对象的准备工作,即初始化过程,但是 最为重要的依赖注入还没有发生,现在在IOC容器中BeanDefinition存储的只是一些静态信息,接下来需要向容器 注册Bean定义信息才能全部完成IOC容器的初始化过程。
让我们继续跟踪程序的执行顺序,接下来我们来分析DefaultBeanDefinitionDocumentReader对Bean定义转换的 Document对象解析的流程中,在其parseDefaultElement方法中完成对Document对象的解析后得到封装 BeanDefinition的BeanDefinitionHold对象,然后调用BeanDefinitionReaderUtils的 registerBeanDefinition方法向IOC容器注册解析的Bean,BeanDefinitionReaderUtils的注册的源码如下:
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
// 以name为key,以BeanDefinition为Value,注册到Registry
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);
}
}
}
当调用BeanDefinitionReaderUtils向IOC容器注册解析的BeanDefinition时,真正完成注册功能的是 DefaultListableBeanFactory。
DefaultListableBeanFactory向IOC容器注册解析后的BeanDefinition:DefaultListableBeanFactory 中使用一个HashMap的集合对象存放IOC容器中注册解析的BeanDefinition,向IOC容器注册的主要源码如下:
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition oldBeanDefinition;
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(oldBeanDefinition)) {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
// 检查是否有同名的BeanDefinition 已经在IOC容器中注册
if (oldBeanDefinition != null || containsSingleton(beanName)) {
// 重置已经注册过的BeanDefinition缓存
resetBeanDefinition(beanName);
}
}
至此,Bean定义资源文件中配置的Bean被解析过后,已经注册到IOC容器中,被容器管理起来,真正完成了IOC容器 初始化所做的全部工作。现在IOC容器中已经建立了整个Bean的配置信息,这些BeanDefinition信息已经可以使 用,并且可以被检索,IOC容器的作用就是对这些注册的Bean定义信息进行处理和维护。这些的注册的Bean定义信息 是IOC容器控制反转的基础,正是有了这些注册的数据,容器才可以进行依赖注入。
总结: 现在通过上面的代码,总结一下IOC容器初始化的基本步骤:
(1).初始化的入口在容器实现中的refresh()调用来完成。
(2).对bean定义载入IOC容器使用的方法是loadBeanDefinition,其中的大致过程如下:
通过ResourceLoader来完成资源文件位置的定位,DefaultResourceLoader是默认的实现,同时上下文本身就给 出了ResourceLoader的实现,可以从类路径,文件系统,URL等方式来定为资源位置。如果是XmlBeanFactory作为 IOC容器,那么需要为它指定bean定义的资源,也就是说bean定义文件时通过抽象成Resource来被IOC容器处理的, 容器通过BeanDefinitionReader来完成定义信息的解析和Bean信息的注册,往往使用的是 XmlBeanDefinitionReader来解析bean的xml定义文件-实际的处理过程是委托给 BeanDefinitionParserDelegate来完成的,从而得到bean的定义信息,这些信息在Spring中使用 BeanDefinition对象来表示-这个名字可以让我们想到loadBeanDefinition,RegisterBeanDefinition这些相关 方法-他们都是为处理BeanDefinitin服务的,容器解析得到BeanDefinition以后,需要把它在IOC容器中注册,这 由IOC实现BeanDefinitionRegistry接口来实现。注册过程就是在IOC容器内部维护的一个HashMap来保存得到的 BeanDefinition的过程。这个HashMap是IOC容器持有Bean信息的场所,以后对Bean的操作都是围绕这个HashMap 来实现的。
然后我们就可以通过BeanFactory和ApplicationContext来享受到SpringIOC的服务了,在使用IOC容器的时候,我 们注意到除了少量粘合代码,绝大多数以正确IOC风格编写的应用程序代码完全不用关心如何到达工厂,因为容器将 把这些对象与容器管理的其他对象钩在一起。基本的策略是把工厂放到已知的地方,最好是放在对预期使用的上下文 有意义的地方,以及代码将实际需要访问工厂的地方。Spring本身提供了对声明式载入web应用程序用法的应用程序 上下文,并将其存储在ServletContext中的框架实现。
在使用SpringIOC容器的时候我们还需要区别两个概念: BeanFactory和FactoryBean,其中BeanFactory指的是IOC容器的编程抽象,比如ApplicationContext, XmlBeanFactory等,这些都是IOC容器的具体表现,需要使用什么样的容器由客户决定,但Spring为我们提供了丰 富的选择。FactoryBean只是一个可以在IOC而容器中被管理的一个Bean,是对各种处理过程和资源使用的抽 象,FactoryBean在需要时产生另一个对象,而不返回FactoryBean本身,我们可以把它看成是一个抽象工厂,对它 的调用返回的是工厂生产的产品。所有的FactoryBean都实现特殊的 org.springframework.beans.factory.FactoryBean接口,当使用容器中FactoryBean的时候,该容器不会返回 FactoryBean本身,而是返回其生成的对象。Spring包括了大部分的通用资源和服务访问抽象的FactoryBean的实 现,其中包括:对JNDI查询的处理,对代理对象的处理,对事务性代理的处理,对RMI代理的处理等,这些我们都可 以看成是具体的工厂,看成是Spring为我们建立好的工厂。也就是说Spring通过使用抽象工厂模式为我们准备了一系 列工厂来生产一些特定的对象,免除我们手工重复的工作,我们要使用时只需要在IOC容器里配置好就能很方便的使 用了。