前言
前面我们梳理了Spring容器初始话的整体流程,今天来单独讲一讲初始化过过程重点之一,Spring配置的解析和BeanDefinition的加载。
虽然Spring的配置有很多形式,不再限于xml文件。但是本文还是以前文的spring-demo项目为例,分析xml形式配置的配置文件spring-beans.xml是如何解析的。掌握xml配置形式之后,再看其他方式,其实就触类旁通了。
原demo扩充
之前demo里内容比较少,我们先丰富一下,然后再分析。项目地址: spring-xml-demo-enhanced
项目结构结构
编码
Component、Component空类
package cn.dingyufan.learnspring.springxmldemoenhanced.component;
import org.springframework.stereotype.Component;
@Component
public class OneComponent {
}
package cn.dingyufan.learnspring.springxmldemoenhanced.component;
import org.springframework.stereotype.Component;
@Component
public class TwoComponent {
}
HelloController增加了oneComponent注入
package cn.dingyufan.learnspring.springxmldemoenhanced.controller;
import cn.dingyufan.learnspring.springxmldemoenhanced.component.OneComponent;
import cn.dingyufan.learnspring.springxmldemoenhanced.service.HelloService;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Autowired
private HelloService helloService;
@Autowired
private OneComponent oneComponent;
// 属性注入之后就可以自动打印,方便验证
@PostConstruct
private void init() {
System.out.println("HelloController.init(),helloService=>" + helloService);
System.out.println("HelloController.init(),oneComponent=>" + oneComponent);
}
@GetMapping("/hello")
public ResponseEntity<String> hello(HttpServletRequest request) {
return ResponseEntity.ok("Hello Spring!");
}
@GetMapping("/check")
public ResponseEntity<String> check(HttpServletRequest request) {
return ResponseEntity.ok(String.valueOf(helloService.hashCode()));
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("HelloController注入applicationContext =>" + applicationContext.getDisplayName());
this.applicationContext = applicationContext;
}
}
HelloService无变化
package cn.dingyufan.learnspring.springxmldemoenhanced.service;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class HelloService implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("HelloService注入applicationContext =>" + applicationContext.getDisplayName());
this.applicationContext = applicationContext;
}
}
WorldService注入了多种内容,一个对象,一个数字,一个数组。都是通过xml配置配置,然后setter方法注入的。init()方法说明一下,这里是在xml配置的init-method项,调用顺序是在bean属性注入之后的,所以我们借助这个方法来检查内容是否注入。
package cn.dingyufan.learnspring.springxmldemoenhanced.service;
import java.util.List;
public class WorldService {
private HelloService helloService;
private Integer year;
private List<String> ultraman;
// 在xml配置了<bean>的init-method属性
private void init() {
System.out.println("WorldService.init(),helloService=>" + helloService);
System.out.println("WorldService.init(),year=>" + year);
System.out.println("WorldService.init(),ultraman=>" + ultraman);
}
public void setHelloService(HelloService helloService) {
this.helloService = helloService;
}
public void setUltraman(List<String> ultraman) {
this.ultraman = ultraman;
}
public void setYear(Integer year) {
this.year = year;
}
}
配置
配置上面,在demo里使用了常见的一些配置标签。
首先可以看到新增了一个spring-component.xml。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!--扫描注册base-package下的组件-->
<context:component-scan base-package="cn.dingyufan.learnspring.springxmldemoenhanced.component"/>
</beans>
spring-beans.xml文件增加了worldService定义,同时为worldService配置了属性;增加了<import>标签,这个作用相当于把spring-component.xml的内容都引入spring-beans.xml。<import>标签可以让我们更加方便的拆分管理bean,避免一个配置文件巨大。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="helloService" class="cn.dingyufan.learnspring.springxmldemoenhanced.service.HelloService"/>
<bean id="worldService" class="cn.dingyufan.learnspring.springxmldemoenhanced.service.WorldService" init-method="init">
<property name="helloService" ref="helloService"/>
<property name="year" value="2021"/>
<property name="ultraman">
<list>
<value>泰罗</value>
<value>赛文</value>
<value>艾斯</value>
</list>
</property>
</bean>
<import resource="spring-component.xml"/>
</beans>
spring-mvc.xml、web.xml、pom.xml都没有变化,不再赘述,需要的话可以从前文获取
运行
从控制台打印的信息可以看到,HelloService中的对象、数字、数组都成功注入;HelloController新添加的oneComponent也已经成功注入。说明我们的配置都已经生效了。
源码解析
从上文可知,配置文件的加载是在beanFactory的刷新过程中的。我们仍然以XmlWebApplicationContext为例,从obtainFreshBeanFactory()方法看起。
AbstractApplicationContext
XmlWebApplicationContext的obtainFreshBeanFactory()方法是其父类AbstractApplicationContext实现
// AbstractApplicationContext.java
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 空方法
refreshBeanFactory();
return getBeanFactory();
}
AbstractRefreshableApplicationContext
而XmlWebApplicationContext的refreshBeanFactory()方法是父类AbstractRefreshableApplicationContext实现。
// AbstractRefreshableApplicationContext.java
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
// 空方法,作用是解析配置加载BeanDefinition
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
XmlWebApplicationContext
到这里这个loadBeanDefinitions(beanFactory)方法终于是XmlWebApplicationContext自己实现了。
// XmlWebApplicationContext.java
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 为BeanFactory创建一个XmlBeanDefinitionReader
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// 为XmlBeanDefinitionReader添加配置
beanDefinitionReader.setEnvironment(getEnvironment());
// 把XmlWebApplicationContext自己设为ResourceLoader
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// 空方法,给子类添加它想要的配置的。又是模板方法模式。
initBeanDefinitionReader(beanDefinitionReader);
// 加载BeanDefinition
loadBeanDefinitions(beanDefinitionReader);
}
我们看到,上面为解析配置准备了一个XmlBeanDefinitionReader,给子类留了自定义配置的口子,然后真正的在另一个入参不同的loadBeanDefinitions(reader)方法。
// XmlWebApplicationContext.java
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (String configLocation : configLocations) {
reader.loadBeanDefinitions(configLocation);
}
}
}
从代码中可以看到,loadBeanDefinitions(reader)方法就是遍历我们的xml配置文件路径,然后依次交给XmlBeanDefinitionReader去处理。
插一句,这个configLocations还记得是哪里来的吗?它是我们在web.xml中配置的context-param,然后在ContextLoader中,从servletContext获取并赋值给applicationContext的。
AbstractBeanDefinitionReader
我们来看XmlBeanDefinitionReader拿到配置文件路径之后,做了什么处理
- 获取ResourceLoader
- 使用ResourceLoader将配置文件加载为Resource
- 遍历加载到的Resource,调用子类方法加载BeanDefinition
// AbstractBeanDefinitionReader.java。是XmlBeanDefinitionReader父类
@Override
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return loadBeanDefinitions(location, null);
}
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
// 这个ResourceLoader就是在前面XmlWebApplicationContext类的loadBeanDefinitions(beanFactory)方法设置的
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException("Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
}
// XmlWebApplicationContext是实现了ResourcePatternResolver接口的
if (resourceLoader instanceof ResourcePatternResolver) {
try {
// 使用ResourceLoader将配置文件加载为Resource
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
int count = loadBeanDefinitions(resources);
if (actualResources != null) {
Collections.addAll(actualResources, resources);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
}
return count;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
Resource resource = resourceLoader.getResource(location);
int count = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
}
return count;
}
}
@Override
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int count = 0;
for (Resource resource : resources) {
// 这里这个loadBeanDefinitions(resource)是子类自己实现
// 对应我们这就是XmlWebApplicationContext中的loadBeanDefinitions(resource)方法
count += loadBeanDefinitions(resource);
}
return count;
}
首先可以看到,它通过getResourceLoader()方法拿到一个ResourceLoader,这个ResourceLoader正是前面XmlWebApplicationContext类的loadBeanDefinitions(beanFactory)方法里,我们给他设置的,设置的值为XmlWebApplicationContext对象本身。可以往上翻一点看看。
然后判断是否是ResourcePatternResolver实现类。我们知道XmlWebApplicationContext是实现了ApplicationContext的,而ApplicationContext接口则是直接继承了ResourcePatternResolver接口的的。
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
@Nullable
String getId();
String getApplicationName();
String getDisplayName();
long getStartupDate();
@Nullable
ApplicationContext getParent();
AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}
我们搜索ResourcePatternResolver的实现类也可以清楚的看到有XmlWebApplicationContext。
然后将配置文件加载为Resource。这个加载是依赖于XmlWebApplicationContext的父类AbstractApplicationContext提供的ResourcePatternResolver类型的成员变量resourcePatternResolver。AbstractApplicationContext的构造方法里,会创建变量实例,是一个PathMatchingResourcePatternResolver。具体过程就先不说了,先知道是哪个类来做这个事。
// AbstractApplicationContext.java
public AbstractApplicationContext() {
this.resourcePatternResolver = getResourcePatternResolver();
}
protected ResourcePatternResolver getResourcePatternResolver() {
return new PathMatchingResourcePatternResolver(this);
}
XmlBeanDefinitionReader
最后AbstractBeanDefinitionReader调用子类XmlBeanDefinitionReader方法解析Resource。又回到XmlWebApplicationContext类,会将Resource包装成EncodedResource;然后以IO流读取文件,将XML文件转换成对应的Document对象,方便程序处理。然后实例化一个BeanDefinitionDocumentReader来读取Document对象。
// XmlBeanDefinitionReader.java
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Loading XML bean definitions from " + encodedResource);
}
// 目前已加载的Resource
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
// inputStream读取Resource,并继续
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
try {
// 解析xml,形成对应的Document对象
Document doc = doLoadDocument(inputSource, resource);
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
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);
}
}
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
DefaultBeanDefinitionDocumentReader
读取Document对象默认的是使用DefaultBeanDefinitionDocumentReader,在方法中又创建了BeanDefinitionParserDelegate代理类。方法这里涉及到了namespace、profile的处理,目前先不细说;两个空方法也没啥可讨论的;主要关注于parseBeanDefinitions(root, this.delegate)。
// DefaultBeanDefinitionDocumentReader.java
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
doRegisterBeanDefinitions(doc.getDocumentElement());
}
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
// 判断是否配置了profile。
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
// We cannot use Profiles.of(...) since profile expressions are not supported
// in XML config. See SPR-12458 for details.
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
在下面这个方法里,分两种情况处理,一种是默认namespace的,另一种其实就是自定义的namespace(自定义标签)。自定义标签的应用在Spring应用也非常广泛,比如我们熟知的SpringMVC、Dubbo等框架都有自定义标签的使用。在这我们只看默认namespace的处理,另一种以后单独讲。
// DefaultBeanDefinitionDocumentReader.java
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);
}
}
对于默认namespace的Node,最后都会来进入parseDefaultElement(ele, delegate)方法。这个方法里的四个if分别解析不同的标签。标签解析大同小异,我们以<bean>的解析为例子。
// DefaultBeanDefinitionDocumentReader.java
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(ele, delegate)方法我们可以看到,下面的方法做了四件事
- 借助解析delegate代理对象解析节点为BeanDefinitionHolder
- 如果定义了装饰器Decorator,会对BeanDefinition进行装饰
- 注册最终的BeanDefinition
- 发送bean注册事件
其实第一步我们是最关心的,我们一会再看负责解析的代理对象是如何处理的。这里提到使用装饰器Decorator,这个是做什么呢,简单说一下。这里其实就是根据节点的namespaceUri寻找对应的NamespaceHandler,然后看NamespaceHandler中是不是注册了处理此节点名称的装饰器Decorator,若有就应用装饰器进行装饰。以后会细说。
// DefaultBeanDefinitionDocumentReader.java
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 解析节点,创建BeanDefinitionHolder
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
// 如果定义了装饰器,会对BeanDefinition进行装饰。
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 注册最终的BeanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex);
}
// 发送bean注册事件
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
BeanDefinitionParserDelegate
我们还是关注BeanDefinitionHolder是怎么来的。delegate解析的主要逻辑如下
- 读取node上的id, name
- 取beanName并检查是否唯一
- 解析得AbstractBeanDefinition
- 根据className, parent类型,以及ClassLoader创建一个AbstractBeanDefinition
- 读取各种属性,填充到AbstractBeanDefinition
- 再次尝试取beanName
- 组装成BeanDefinitionHolder
// BeanDefinitionParserDelegate.java
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
// 读取node上的id, name
String id = ele.getAttribute(ID_ATTRIBUTE);
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));
}
// beanName默认是id, 如果id没配name配了,就取第一个name做id
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isTraceEnabled()) {
logger.trace("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases");
}
}
if (containingBean == null) {
// 检查beanName是否重复,重复则抛出异常
checkNameUniqueness(beanName, aliases, ele);
}
// 解析节点到AbstractBeanDefinition
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
// = =这一大段就是,如果没有beanName就生成一个beanName
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null
&& beanName.startsWith(beanClassName)
&& beanName.length() > beanClassName.length()
&&!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isTraceEnabled()) {
logger.trace("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);
// AbstractBeanDefinition、beanName, aliases组装成BeanDefinitionHolder
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
@Nullable
public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
// 读取node中的class属性
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
// 读取node中的parent属性
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
try {
// 根据className, parent类型,以及ClassLoader创建一个AbstractBeanDefinition
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
// 读取各种属性,填充到AbstractBeanDefinition。如:
// singleton、scope、abstract、lazy-init、autowire、depends-on、autowire-candidate、
// primary、init-method、destroy-method、factory-method、factory-bean
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
// 解析descriptionb标签
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);
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;
}
结语
洋洋洒洒写了一大段,可能用一张图来表示一下流程可能会更清晰一些。