Spring源码解析之一 解析配置以及注册Bean
Spring是一个开放源代码的设计层面框架, 解决的是业务逻辑层和其他各层的松耦合问题, 因此它将面向接口的编程思想贯穿整个系统应用.
1. XmlBeanDefinitionReader介绍
XML配置文件的读取与解析是Spring中比较重要的功能, 因为Spring的大部分功能都是以配置作为切入点, 可以从XmlBeanDefinitionReader中梳理下资源读取、解析以及注册的大致脉络.
- ResourceLoader: 定义资源加载器, 主要应用于根据给定的资源文件地址返回对应的Resource.
- BeanDefinitionReader: 主要定义资源文件读取并转换为BeanDefinition的各个功能.
- EnvironmentCapable: 定义获取Environment方法.
- DocumentLoader: 定义从资源文件加载到转换为Document的功能.
- AbstractBeanDefinitionReader: 对EnvironmentCapable、BeanDefinitionReader类定义的功能进行实现.
- BeanDefinitionDocumentReader: 定义读取Document并注册BeanDefinition功能.
- BeanDefinitionParserDelegate: 定义解析Element的各种方法.
2. 代码解析
2.1 加载配置文件
了解了几个核心类之后, 我们来分析下XmlBeanFactory. 虽然该类被标注@Deprecated, 但该类是了解XmlBeanDefinitionReader的最佳途径, 其内部直接持有XmlBeanDefinitionReader对象用来解析XML配置.
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
// 此处才是资源加载的真正实现.
this.reader.loadBeanDefinitions(resource);
}
}
在分析this.reader.loadBeanDefinitions(resource)方法前, 先看下super()中的代码, 此处直接追踪到父类AbstractAutowireCapableBeanFactory的构造函数中.
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
private final Set<Class<?>> ignoredDependencyInterfaces = new HashSet<>();
public AbstractAutowireCapableBeanFactory() {
super();
ignoreDependencyInterface(BeanNameAware.class);
ignoreDependencyInterface(BeanFactoryAware.class);
ignoreDependencyInterface(BeanClassLoaderAware.class);
}
public void ignoreDependencyInterface(Class<?> ifc) {
this.ignoredDependencyInterfaces.add(ifc);
}
}
这里需要关注的是ignoreDependencyInterface方法, 其主要功能是忽略给定接口的自动装配.
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
// 关于Spring中Resource接口及其相关实现类查看google说明.
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
// 使用一个ThreadLocal来存放配置文件.
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException("");
}
try {
// 从EncodedResource中获取输入流, 根据流创建org.xml.sax.InputSource类
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
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();
}
}
}
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
try {
Document doc = doLoadDocument(inputSource, resource); // 加载XML文件, 并得到对应的Document.
return registerBeanDefinitions(doc, resource); // 根据返回的Document注册Bean信息.
} catch (Exception ex) {
throw ex;
}
}
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
getValidationModeForResource(resource), // 获取对XML文件的验证模式
isNamespaceAware());
}
}
上述代码只是Spring加载解析配置文件的开始, 在分析registerBeanDefinitions方法之前, 先从获取XML文件的验证模式说起.
2.1.1 XML验证模式
了解XML文件的都应该知道, XML文件的验证模式保证了XML文件的正确性, 而XML的验证模式大致可以分为DTD和XSD. DTD在现在基本被淘汰, 可以直接忽略, 此处直接介绍XSD.
XSD描述了XML文档的结构, 可以用一个指定的XML Schema来验证某个XML文档, 以检查XML文档是否符合其要求. 在验证时, 除了要声明空间外(xmlns="http://www.springframework.org/schema/beans"), 还必须指定该名称空间对应的XML Schema文档的存储位置(xsi:schemaLocation="..."). 它包含两部分, 一部分是名称空间的uri, 另一部分就是该名称空间所标识的XML Schema文件位置或URL地址.
<?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">
</beans>
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
protected int getValidationModeForResource(Resource resource) {
int validationModeToUse = getValidationMode();
// 如果手动指定了验证模式, 则使用指定的验证模式.
if (validationModeToUse != VALIDATION_AUTO) {
return validationModeToUse;
}
// 自动检测
int detectedMode = detectValidationMode(resource);
if (detectedMode != VALIDATION_AUTO) {
return detectedMode;
}
return VALIDATION_XSD;
}
protected int detectValidationMode(Resource resource) {
if (resource.isOpen()) {
throw new BeanDefinitionStoreException();
}
InputStream inputStream;
try {
inputStream = resource.getInputStream();
} catch (IOException ex) {
throw new BeanDefinitionStoreException("..", ex);
}
try {
return this.validationModeDetector.detectValidationMode(inputStream);
} catch (IOException ex) {
throw new BeanDefinitionStoreException("..", ex);
}
}
}
public class XmlValidationModeDetector {
public int detectValidationMode(InputStream inputStream) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
try {
boolean isDtdValidated = false;
String content;
while ((content = reader.readLine()) != null) {
content = consumeCommentTokens(content);
// 如果读取的行是空或者是注释则略过.
if (this.inComment || !StringUtils.hasText(content)) {
continue;
}
// 是否包含DOCTYPE, 如果包含的话就是DTD模式
if (hasDoctype(content)) {
isDtdValidated = true;
break;
}
// 读取到<开始符号, 验证模式一定会在开始符号之前.
if (hasOpeningTag(content)) {
// End of meaningful data...
break;
}
}
return (isDtdValidated ? VALIDATION_DTD : VALIDATION_XSD);
} catch (CharConversionException ex) {
return VALIDATION_AUTO;
} finally {
reader.close();
}
}
}
2.1.2 获取Document
XML验证完成之后, 即可以进行Document加载了.
public class DefaultDocumentLoader implements DocumentLoader {
@Override
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
return builder.parse(inputSource);
}
protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware) throws ParserConfigurationException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(namespaceAware);
if (validationMode != XmlValidationModeDetector.VALIDATION_NONE) {
factory.setValidating(true);
if (validationMode == XmlValidationModeDetector.VALIDATION_XSD) {
factory.setNamespaceAware(true);
try {
factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE, XSD_SCHEMA_LANGUAGE);
} catch (IllegalArgumentException ex) {
ParserConfigurationException pcex = new ParserConfigurationException("");
pcex.initCause(ex);
throw pcex;
}
}
}
return factory;
}
protected DocumentBuilder createDocumentBuilder(DocumentBuilderFactory factory, EntityResolver entityResolver, ErrorHandler errorHandler) throws ParserConfigurationException {
DocumentBuilder docBuilder = factory.newDocumentBuilder();
if (entityResolver != null) {
docBuilder.setEntityResolver(entityResolver);
}
if (errorHandler != null) {
docBuilder.setErrorHandler(errorHandler);
}
return docBuilder;
}
}
对于这部分代码并没有太多可以描述的, 因为SAX解析XML的代码基本都是类似的. 先创建DocumentBuilderFactory, 再通过DocumentBuilderFactory创建DocumentBuilder, 进而解析inputSource来返回Document对象. 此处需要注意的是, 在createDocumentBuilder方法参数中, 传入通过getEntityResolver方法获取的返回值.
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
getValidationModeForResource(resource), isNamespaceAware());
}
protected EntityResolver getEntityResolver() {
if (this.entityResolver == null) {
// Determine default EntityResolver to use.
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader != null) {
this.entityResolver = new ResourceEntityResolver(resourceLoader);
} else {
this.entityResolver = new DelegatingEntityResolver(getBeanClassLoader());
}
}
return this.entityResolver;
}
}
2.1.3 EntityResolver用法
如果SAX解析XML时, 需要实现自定义处理外部实体, 则必须实现此接口并使用setEntityResolver方法向SAX驱动器注册一个实例, 这就是EntityResolver的主要用途. 也就是说, 解析一个XML, SAX首先读取XML文档上的声明, 根据声明去寻找相应的DTD定义. 默认的寻找规则就是通过网络下载相应的DTD声明并进行验证. EntityResolver的作用是项目本身就可以提供一个如何寻找DTD声明的方法, 比如我们将DTD文件直接存放在项目的某处, 在实现时直接将此文档读取并返回给SAX即可.
2.2 解析Document
在文件转换为Document之后, 接下来就是如何解析Document了, 回到XmlBeanDefinitionReader中的doLoadBeanDefinitions方法中, 查看registerBeanDefinitions方法的具体实现.
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader, EnvironmentCapable {
private final BeanDefinitionRegistry registry;
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
this.registry = registry;
}
@Override
public final BeanDefinitionRegistry getRegistry() {
return this.registry;
}
}
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
private Class<? extends BeanDefinitionDocumentReader> documentReaderClass = DefaultBeanDefinitionDocumentReader.class;
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
// 需要注意此处的registry参数. 默认使用BeanDefinitionRegistry的子类DefaultListableBeanFactory
super(registry);
}
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
try {
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource); // 进入该方法.
} catch (Exception ex) {
throw ex;
}
}
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// 此处实例化BeanDefinitionDocumentReader的子类DefaultBeanDefinitionDocumentReader.
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
// 记录统计前BeanDefinition的加载个数
int countBefore = getRegistry().getBeanDefinitionCount();
// 加载及注册Bean
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
// 返回本次加载的BeanDefinition个数
return getRegistry().getBeanDefinitionCount() - countBefore;
}
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
return BeanUtils.instantiateClass(this.documentReaderClass);
}
}
此处将解析Document的任务委托给了BeanDefinitionDocumentReader的子类DefaultBeanDefinitionDocumentReader. 进入DefaultBeanDefinitionDocumentReader类, 可以看到核心方法: doRegisterBeanDefinitions方法. 如果前面一直是XML加载解析的准备阶段, 那么doRegisterBeanDefinitions算是真正地开始进行解析了.
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
private XmlReaderContext readerContext;
private BeanDefinitionParserDelegate delegate;
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
doRegisterBeanDefinitions(doc.getDocumentElement());
}
protected void doRegisterBeanDefinitions(Element root) {
// 处理解析的具体类, 此处的BeanDefinitionParserDelegate是一个比较重要的类, 负责解析Bean的定义.
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
// 获取<beans profile='xxx'>中的profile, 判断是否是当前环境.
// 如果当前激活的profile不是此处获取的profile, 那么不会对<beans>进行解析
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)) {
return;
}
}
}
preProcessXml(root); // 解析前处理, 留给子类实现.
parseBeanDefinitions(root, this.delegate);
postProcessXml(root); // 解析后处理, 留给子类实现.
this.delegate = parent;
}
protected BeanDefinitionParserDelegate createDelegate(XmlReaderContext readerContext, Element root, @Nullable BeanDefinitionParserDelegate parentDelegate) {
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
delegate.initDefaults(root, parentDelegate);
return delegate;
}
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
// 使用node.getNamespaceURI()获取命名空间, 之后与Spring中固定的命名空间(http://www.springframework.org/schema/beans)进行对比以此判断是否是默认命名空间
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); // 自定义解析
}
}
}
parseDefaultElement解析的节点是import、alias、bean、beans这四个. 之所以是这四个, 是因为他们处于http://www.springframework.org/schema/beans这个namespace中. 在使用其他标签(mvc、task、context等)时, xml中需要引入相应的namespace和xsd文件, 同时代码中需要提供相应的parser来解析, 如MvcNamespaceHandler、TaskNamespaceHandler、ContextNamespaceHandler等.
2.3 解析默认标签
默认标签的解析是在parseDefaultElement中进行的, 分别对4中不同标签(import、alias、bean、beans)做了不同的处理.
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { // import
importBeanDefinitionResource(ele);
} else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { // alias
processAliasRegistration(ele);
} else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { // bean
processBeanDefinition(ele, delegate);
} else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // beans
doRegisterBeanDefinitions(ele);
}
}
}
2.3.1 解析bean标签
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 委托BeanDefinitionParserDelegate的parseBeanDefinitionElement方法进行元素解析,
// 返回的bdHolder中已经包含了配置文件中的各种属性了, 比如class、name、id等等.
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
// 如果默认标签的子节点存在自定义的属性, 则再次对自定义标签进行解析.
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 解析完成后进行注册. 该操作委托给了BeanDefinitionReaderUtils.
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
} catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex);
}
// 发出响应事件, 通知相关的监听器.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
}
在继续分析之前, 我们先看下 <bean /> 标签中可以定义哪些属性(部分重要属性):
| 名称 | 说明 |
|---|---|
| class | 类的全限定名 |
| name | 可指定 id、name(用逗号、分号、空格分隔) |
| scope | 作用域 |
| constructor arguments | 指定构造参数 |
| properties | 设置属性的值 |
| autowiring mode | no(默认值)、byName、byType、 constructor |
| lazy-initialization mode | 是否懒加载(如果被非懒加载的bean依赖了那么其实也就不能懒加载了) |
| initialization method | bean 属性设置完成后, 会调用这个方法 |
| destruction method | bean 销毁后的回调方法 |
一个简单bean配置就像下面这样
<bean id="exampleBean" name="name1, name2, name3" class="com.javadoop.ExampleBean"
scope="singleton" lazy-init="true" init-method="init" destroy-method="cleanup">
<constructor-arg type="int" value="7500000"/>
<property name="beanTwo" ref="yetAnotherBean"/>
</bean>
继续分析代码, 接下来进入BeanDefinitionParserDelegate的parseBeanDefinitionElement方法中.
public class BeanDefinitionParserDelegate {
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List<String> aliases = new ArrayList<>();
// 切分name属性并添加到alias集合中
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id; // 生成beanName, 如果没有ID属性的话, 那么就使用alias中的第一个.
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
}
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
// 根据bean标签中的配置创建BeanDefinition, 运行本行代码之后, 整个bean标签就算是解析完成了.
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
// 如果没有设置id或者name(beanName还是为空)的话, 此时就会根据Spring中提供的命名规则为当前bean生成beanName.
if (!StringUtils.hasText(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);
}
}
} catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
// 解析class属性
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
// 解析parent属性
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
try {
// 创建BeanDefinition的子类GenericBeanDefinition
AbstractBeanDefinition bd = createBeanDefinition(className, parent); // 1. 创建BeanDefinition
// 设置BeanDefinition的一些属性, 这些属性都定义在AbstractBeanDefinition中.
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); // 2. 解析各种属性
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
// 解析bean标签中的子标签
parseMetaElements(ele, bd); // 3. 解析子元素meta
parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); // 4. 解析子元素lookup-method
parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); // 5. 解析子元素replace-method
parseConstructorArgElements(ele, bd); // 6. 解析子元素constructor-arg
parsePropertyElements(ele, bd); // 7. 解析子元素property
parseQualifierElements(ele, bd); // 8. 解析子元素qualifier
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
} catch (Exception ex) {
// ...
} finally {
this.parseState.pop();
}
return null;
}
}
上述代码就是对默认标签解析的全过程了. 主要可以分为以下几个步骤.
1. 创建BeanDefinition
BeanDefinition是一个接口, 表示配置文件中bean标签在容器中的内部表现形式, 在Spring中存在三种实现: RootBeanDefinition、ChildBeanDefinition、GenericBeanDefinition, 三种实现均继承自AbstractBeanDefinition. 在配置文件中可以定义父bean和子bean, 父bean使用RootBeanDefinition表示, 而子bean用ChildBeanDefinition表示, 而没有父bean的bean就使用RootBeanDefinition表示.
由此可见, 要解析属性首先要创建用于承载属性的实例: GenericBeanDefinition. 而代码createBeanDefinition(className, parent)的作用就是实现此功能.
public class BeanDefinitionParserDelegate {
protected AbstractBeanDefinition createBeanDefinition(@Nullable String className,
@Nullable String parentName) throws ClassNotFoundException {
return BeanDefinitionReaderUtils.createBeanDefinition(parentName, className, this.readerContext.getBeanClassLoader());
}
}
public abstract class BeanDefinitionReaderUtils {
public static AbstractBeanDefinition createBeanDefinition(@Nullable String parentName,
@Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {
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;
}
}
2. 解析各种属性
创建完BeanDefinition实例后, 便可以对bean信息的各种属性进行解析了, 首先进入parseBeanDefinitionAttributes方法, 该方法是对element所有元素属性进行解析.
public class BeanDefinitionParserDelegate {
// 设置BeanDefinition的一些属性, 这些属性都定义在AbstractBeanDefinition中.
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
@Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {
// scope
if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) { // singleton不再被支持, 替换为scope
error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
} else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
} else if (containingBean != null) {
// 在嵌入BeanDefinition情况下并且没有单独制定scope属性, 默认使用父类的属性.
bd.setScope(containingBean.getScope());
}
// abstract
if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
}
// lazy-init
String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
if (isDefaultValue(lazyInit)) {
lazyInit = this.defaults.getLazyInit();
}
bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
// autowire
String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
bd.setAutowireMode(getAutowireMode(autowire));
// depends-on
if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
}
// autowire-candidate
String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
if (isDefaultValue(autowireCandidate)) {
String candidatePattern = this.defaults.getAutowireCandidates();
if (candidatePattern != null) {
String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
}
} else {
bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
}
// primary
if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
}
// init-method
if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
bd.setInitMethodName(initMethodName);
} else if (this.defaults.getInitMethod() != null) {
bd.setInitMethodName(this.defaults.getInitMethod());
bd.setEnforceInitMethod(false);
}
// destroy-method
if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
bd.setDestroyMethodName(destroyMethodName);
} else if (this.defaults.getDestroyMethod() != null) {
bd.setDestroyMethodName(this.defaults.getDestroyMethod());
bd.setEnforceDestroyMethod(false);
}
// factory-method
if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
}
// factory-bean
if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
}
return bd;
}
}
上述代码中可以清晰的看到Spring完成了对所有属性的解析, 这些属性有些事我们经常使用到的, 不了解的可以查阅相关资料.
3. 解析子元素meta
在开始解析meta之前, 先看下如何使用meta属性.
<bean id="bean1" class="com.Bean1">
<meta key="metaName" value="metaValue" />
</bean>
这段代码不会体现在bean1的属性中, 而是一个额外的声明, 当需要时可以通过BeanDefinition的getAttribute(key)方法进行获取.
public class BeanDefinitionParserDelegate {
public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {
NodeList nl = ele.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
// 提取meta数据
if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) {
Element metaElement = (Element) node;
String key = metaElement.getAttribute(KEY_ATTRIBUTE); // key
String value = metaElement.getAttribute(VALUE_ATTRIBUTE); // value
BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
attribute.setSource(extractSource(metaElement));
attributeAccessor.addMetadataAttribute(attribute);
}
}
}
}
4. 解析子元素lookup-method
子元素lookup-method可以用在设计有些可插拔的功能上.
public class ClassA {
public String method() {
System.out.println("classA");
}
}
public abstract class ClassB {
public void print() {
this.getClassA().method();
}
public abstract ClassA getClassA();
}
<bean id="classA" class="com.classA" />
<bean id="classB" class="com.ClassB">
<lookup-method name="getClassA" bean="classA" />
</bean>
在ClassB中, 并没有实现抽象方法getClassA(), 而在配置文件中, 动态的将classA这个bean作为getClassA的返回值.
public class BeanDefinitionParserDelegate {
public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) {
NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
// 解析lookup-method标签
if (isCandidateElement(node) && nodeNameEquals(node, LOOKUP_METHOD_ELEMENT)) {
Element ele = (Element) node;
String methodName = ele.getAttribute(NAME_ATTRIBUTE);
String beanRef = ele.getAttribute(BEAN_ELEMENT);
LookupOverride override = new LookupOverride(methodName, beanRef);
override.setSource(extractSource(ele));
overrides.addOverride(override);
}
}
}
}
上述代码与parseMetaElements类似, 最大的区别是在if判断中被修改为LOOKUP_METHOD_ELEMENT.
5. 解析子元素replace-method
该标签可以在运行时用新的方法替换现有的方法.
public class ClassA {
public void method() {
System.out.println("classA");
}
}
public class ClassB implements MethodReplacer {
@override
public Object reimplement(Object obj, Method method, Object[] args) throws Throwable {
System.out.println("classB");
}
}
<bean id="classA" class="com.classA" />
<bean id="classB" class="com.ClassB">
<replace-method name="method" replacer="classA" />
</bean>
以上就是标签replace-method的使用方式, 接下来分析下Spring是如何解析replace-method的.
public class BeanDefinitionParserDelegate {
public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) {
NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
// 解析replace-method
if (isCandidateElement(node) && nodeNameEquals(node, REPLACED_METHOD_ELEMENT)) {
Element replacedMethodEle = (Element) node;
// 提取需要替换的旧方法
String name = replacedMethodEle.getAttribute(NAME_ATTRIBUTE);
// 提取对应的新方法
String callback = replacedMethodEle.getAttribute(REPLACER_ATTRIBUTE);
ReplaceOverride replaceOverride = new ReplaceOverride(name, callback);
// Look for arg-type match elements.
List<Element> argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, ARG_TYPE_ELEMENT);
for (Element argTypeEle : argTypeEles) {
// 记录参数
String match = argTypeEle.getAttribute(ARG_TYPE_MATCH_ATTRIBUTE);
match = (StringUtils.hasText(match) ? match : DomUtils.getTextValue(argTypeEle));
if (StringUtils.hasText(match)) {
replaceOverride.addTypeIdentifier(match);
}
}
replaceOverride.setSource(extractSource(replacedMethodEle));
overrides.addOverride(replaceOverride);
}
}
}
}
6. 解析子元素constructor-arg
接下来就是解析构造函数标签(constructor-arg)了.
public class BeanDefinitionParserDelegate {
public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (isCandidateElement(node) && nodeNameEquals(node, CONSTRUCTOR_ARG_ELEMENT)) {
// 解析constructor-arg标签
parseConstructorArgElement((Element) node, bd);
}
}
}
public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
// 获取index属性
String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);
// 获取type属性
String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);
// 获取name属性
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
if (StringUtils.hasLength(indexAttr)) {
try {
int index = Integer.parseInt(indexAttr);
if (index < 0) {
error("'index' cannot be lower than 0", ele);
} else {
try {
this.parseState.push(new ConstructorArgumentEntry(index));
// 解析constructor-arg上的属性和子元素
Object value = parsePropertyValue(ele, bd, null);
// 封装解析出来的元素
ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
if (StringUtils.hasLength(typeAttr)) {
valueHolder.setType(typeAttr);
}
if (StringUtils.hasLength(nameAttr)) {
valueHolder.setName(nameAttr);
}
valueHolder.setSource(extractSource(ele));
// 不允许重复指定相同的参数
if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
error("Ambiguous constructor-arg entries for index " + index, ele);
} else {
bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
}
} finally {
this.parseState.pop();
}
}
} catch (NumberFormatException ex) {
error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele);
}
} else {
try {
this.parseState.push(new ConstructorArgumentEntry());
Object value = parsePropertyValue(ele, bd, null);
ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
if (StringUtils.hasLength(typeAttr)) {
valueHolder.setType(typeAttr);
}
if (StringUtils.hasLength(nameAttr)) {
valueHolder.setName(nameAttr);
}
valueHolder.setSource(extractSource(ele));
bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
} finally {
this.parseState.pop();
}
}
}
// 解析constructor-arg上的属性和子元素
public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) {
String elementName = (propertyName != null ?
"<property> element for property '" + propertyName + "'" :
"<constructor-arg> element");
// 一个属性对应一种类型: ref、value、list等等
NodeList nl = ele.getChildNodes();
Element subElement = null;
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
// 对应description或者meta不做处理
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;
}
}
}
// 判断constructor-arg上是否有ref属性
boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
// 判断constructor-arg上是否有value属性
boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
if ((hasRefAttribute && hasValueAttribute) || // 同时有ref属性和value属性
((hasRefAttribute || hasValueAttribute) && subElement != null)) { // 存在ref或者value, 并且有子元素
error(elementName + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
}
if (hasRefAttribute) {
// ref属性处理
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) {
// value属性处理
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;
}
}
// 解析constructor-arg下的子元素
public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd, @Nullable String defaultValueType) {
if (!isDefaultNamespace(ele)) {
// 自定义标签解析, 后续会讲
return parseNestedCustomElement(ele, bd);
} else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
// bean标签解析
BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
if (nestedBd != null) {
// 自定义标签解析
nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
}
return nestedBd;
} else if (nodeNameEquals(ele, REF_ELEMENT)) {
// ref标签
String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
boolean toParent = false;
if (!StringUtils.hasLength(refName)) {
refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
toParent = true;
if (!StringUtils.hasLength(refName)) {
error("'bean' or 'parent' is required for <ref> element", ele);
return null;
}
}
if (!StringUtils.hasText(refName)) {
error("<ref> element contains empty target attribute", ele);
return null;
}
RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
ref.setSource(extractSource(ele));
return ref;
} else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
// idref标签
return parseIdRefElement(ele);
} else if (nodeNameEquals(ele, VALUE_ELEMENT)) {
// value标签
return parseValueElement(ele, defaultValueType);
} else if (nodeNameEquals(ele, NULL_ELEMENT)) {
// null标签
TypedStringValue nullHolder = new TypedStringValue(null);
nullHolder.setSource(extractSource(ele));
return nullHolder;
} else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {
// array标签
return parseArrayElement(ele, bd);
} else if (nodeNameEquals(ele, LIST_ELEMENT)) {
// list标签
return parseListElement(ele, bd);
} else if (nodeNameEquals(ele, SET_ELEMENT)) {
// set标签
return parseSetElement(ele, bd);
} else if (nodeNameEquals(ele, MAP_ELEMENT)) {
// map标签
return parseMapElement(ele, bd);
} else if (nodeNameEquals(ele, PROPS_ELEMENT)) {
// props标签
return parsePropsElement(ele);
} else {
error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
return null;
}
}
}
上述代码的逻辑比较清晰, 依次解析constructor-arg中的属性以及其子标签.
7. 解析子元素property
解析子元素property, 没啥好说的, 直接看代码.
public class BeanDefinitionParserDelegate {
public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
// 解析子元素property
parsePropertyElement((Element) node, bd);
}
}
}
public void parsePropertyElement(Element ele, BeanDefinition bd) {
// 解析property上的name属性
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;
}
// parsePropertyValue方法参照constructor-arg标签时的代码说明
Object val = parsePropertyValue(ele, bd, propertyName);
PropertyValue pv = new PropertyValue(propertyName, val);
parseMetaElements(ele, pv); // 参照meta标签的说明
pv.setSource(extractSource(ele));
bd.getPropertyValues().addPropertyValue(pv);
} finally {
this.parseState.pop();
}
}
}
8. 解析子元素qualifier
这个标签指定自动注入时bean的名称, 可以查看注解@Qualifier.
public class BeanDefinitionParserDelegate {
public void parseQualifierElements(Element beanEle, AbstractBeanDefinition bd) {
NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ELEMENT)) {
parseQualifierElement((Element) node, bd);
}
}
}
public void parseQualifierElement(Element ele, AbstractBeanDefinition bd) {
// qualifier标签属性type
String typeName = ele.getAttribute(TYPE_ATTRIBUTE);
if (!StringUtils.hasLength(typeName)) {
error("Tag 'qualifier' must have a 'type' attribute", ele);
return;
}
this.parseState.push(new QualifierEntry(typeName));
try {
AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(typeName);
qualifier.setSource(extractSource(ele));
// qualifier标签属性value
String value = ele.getAttribute(VALUE_ATTRIBUTE);
if (StringUtils.hasLength(value)) {
qualifier.setAttribute(AutowireCandidateQualifier.VALUE_KEY, value);
}
NodeList nl = ele.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ATTRIBUTE_ELEMENT)) {
// 解析qualifier下的子标签attribute
Element attributeEle = (Element) node;
String attributeName = attributeEle.getAttribute(KEY_ATTRIBUTE);
String attributeValue = attributeEle.getAttribute(VALUE_ATTRIBUTE);
if (StringUtils.hasLength(attributeName) && StringUtils.hasLength(attributeValue)) {
BeanMetadataAttribute attribute = new BeanMetadataAttribute(attributeName, attributeValue);
attribute.setSource(extractSource(attributeEle));
qualifier.addMetadataAttribute(attribute);
} else {
error("Qualifier 'attribute' tag must have a 'name' and 'value'", attributeEle);
return;
}
}
}
bd.addQualifier(qualifier);
} finally {
this.parseState.pop();
}
}
}
9. bean标签下的自定义属性
回到DefaultBeanDefinitionDocumentReader的processBeanDefinition方法中, 分析完delegate.parseBeanDefinitionElement(ele)之后开始详细分析delegate.decorateBeanDefinitionIfRequired(ele, bdHolder).
<bean id="classA" class="com.ClassA">
<myBean:user name="name" />
</bean>
在Spring的配置中, 如果bean标签下使用了自定义标签时, delegate.decorateBeanDefinitionIfRequired(ele, bdHolder)便会起作用了.
public class BeanDefinitionParserDelegate {
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) {
// 第三个参数是父类Bean, 当对某个嵌套配置进行分析时(查看BeanDefinitionParserDelegate中parsePropertySubElement方法内解析bean标签代码),
// 这里需要传递父BeanDefinition. 分析代码可知, 其实是为了使用父类的scope属性
return decorateBeanDefinitionIfRequired(ele, definitionHolder, null);
}
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder, @Nullable BeanDefinition containingBd) {
BeanDefinitionHolder finalDefinition = definitionHolder;
NamedNodeMap attributes = ele.getAttributes();
// 遍历所有属性, 查看是否有适用于修饰的属性.
for (int i = 0; i < attributes.getLength(); i++) {
Node node = attributes.item(i);
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}
// 遍历所有的子节点, 查看是否有适用于修饰的属性.
NodeList children = ele.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}
}
return finalDefinition;
}
public BeanDefinitionHolder decorateIfRequired(Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
// 获取自定义标签的命名空间
String namespaceUri = getNamespaceURI(node);
if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
// 根据命名空间找到对应的处理器
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler != null) {
// 此处进行修饰, 这部分会在解析自定义标签时详细说明.
BeanDefinitionHolder decorated = handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
if (decorated != null) {
return decorated;
}
} else if (namespaceUri.startsWith("http://www.springframework.org/")) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
} else {
if (logger.isDebugEnabled()) {
logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
}
}
}
return originalDef;
}
}
10. 注册Bean
当bean标签解析完成后, 回到DefaultBeanDefinitionDocumentReader中processBeanDefinition方法内, 可以看到接下来调用了BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry())开始注册bean. 简单来说就是将BeanDefinition存放到两个map中, 分别对应beanName和alias.
public abstract class BeanDefinitionReaderUtils {
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
// 根据beanName注册
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// 根据alias注册
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
}
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16);
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属性中的methodOverrides校验,
// 校验methodOverrides是否与工厂方法并存或者methodOverrides对应的方法不存在
((AbstractBeanDefinition) beanDefinition).validate();
} catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
// 已经注册的beanName, 并且配置中配置了不允许覆盖, 抛出异常.
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
} else if (existingDefinition.getRole() < beanDefinition.getRole()) {
logger.info("...");
} else if (!beanDefinition.equals(existingDefinition)) {
logger.info("...");
} else {
logger.info("...");
}
// 直接覆盖
this.beanDefinitionMap.put(beanName, beanDefinition);
} else {
if (hasBeanCreationStarted()) { // 是否到启动阶段
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
// 注册到Map中
this.beanDefinitionMap.put(beanName, beanDefinition);
// 使用新的beanDefinitionNames替换旧的
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
// 从集合中移除beanName
removeManualSingletonName(beanName);
}
} else {
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
// 重置所有beanName对应的缓存
resetBeanDefinition(beanName);
}
}
private void removeManualSingletonName(String beanName) {
updateManualSingletonNames(set -> set.remove(beanName), set -> set.contains(beanName));
}
private void updateManualSingletonNames(Consumer<Set<String>> action, Predicate<Set<String>> condition) {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
// manualSingletonNames中存在beanName, 则删除
if (condition.test(this.manualSingletonNames)) { // 存在
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
action.accept(updatedSingletons);
this.manualSingletonNames = updatedSingletons;
}
}
} else {
// manualSingletonNames中存在beanName, 则删除
if (condition.test(this.manualSingletonNames)) {
action.accept(this.manualSingletonNames);
}
}
}
}
public class SimpleAliasRegistry implements AliasRegistry {
private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16);
public void registerAlias(String name, String alias) {
Assert.hasText(name, "'name' must not be empty");
Assert.hasText(alias, "'alias' must not be empty");
synchronized (this.aliasMap) {
// beanName与alias相同, 不记录alias, 并且删除对应的alias
if (alias.equals(name)) {
this.aliasMap.remove(alias);
} else {
String registeredName = this.aliasMap.get(alias);
if (registeredName != null) {
if (registeredName.equals(name)) {
return;
}
// 不允许覆盖, 抛出异常
if (!allowAliasOverriding())
throw new IllegalStateException("...");
}
// 如果A->B存在, 再次出现A->C时会抛出异常
checkForAliasCircle(name, alias);
this.aliasMap.put(alias, name);
}
}
}
}
2.3.2 解析alias标签
在对bean进行定义时, 除了使用bean标签中的id或者name属性来指定名称外, 可以使用alias标签提供多个名称, 例如以下配置
<bean id="classA" name="classA1" class="com.ClassA" />
<bean id="classB" class="com.ClassB" />
<alias name="classB" alias="classB1,classB2" />
接下来回到DefaultBeanDefinitionDocumentReader的parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)方法中, 详细看下processAliasRegistration(ele);方法时如何解析的.
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
protected void processAliasRegistration(Element ele) {
// 获取beanName
String name = ele.getAttribute(NAME_ATTRIBUTE);
// 获取alias
String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
boolean valid = true;
if (!StringUtils.hasText(name)) {
getReaderContext().error("Name must not be empty", ele);
valid = false;
}
if (!StringUtils.hasText(alias)) {
getReaderContext().error("Alias must not be empty", ele);
valid = false;
}
if (valid) {
try {
// 注册alias
// 此处获取的AliasRegistry其实是DefaultListableBeanFactory, 可以查看创建XmlBeanDefinitionReader时的代码.
getReaderContext().getRegistry().registerAlias(name, alias);
} catch (Exception ex) {
getReaderContext().error("Failed to register alias '" + alias + "' for bean with name '" + name + "'", ele, ex);
}
// 注册完成后通知监听器做响应的处理.
getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));
}
}
}
2.3.3 解析import标签
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
protected void importBeanDefinitionResource(Element ele) {
// 获取resource属性
String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
if (!StringUtils.hasText(location)) {
getReaderContext().error("Resource location must not be empty", ele);
return;
}
// 解析系统属性, 比如${user.dir}
location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
Set<Resource> actualResources = new LinkedHashSet<>(4);
// 判断location是绝对路径还是相对路径
boolean absoluteLocation = false;
try {
absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
} catch (URISyntaxException ex) {
}
if (absoluteLocation) {
// 绝对路径, 根绝地址加载相应的配置文件
try {
// 回到loadBeanDefinitions方法, 重复加载 -> 解析 -> 注册的逻辑
int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
} catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to import bean definitions from URL location [" + location + "]", ele, ex);
}
} else {
// 相对路径, 根据相对路径计算出绝对路径
try {
int importCount;
//
Resource relativeResource = getReaderContext().getResource().createRelative(location);
if (relativeResource.exists()) {
// 回到loadBeanDefinitions方法, 重复加载 -> 解析 -> 注册的逻辑
importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
actualResources.add(relativeResource);
} else {
String baseLocation = getReaderContext().getResource().getURL().toString();
// 回到loadBeanDefinitions方法, 重复加载 -> 解析 -> 注册的逻辑
importCount = getReaderContext().getReader().loadBeanDefinitions(
StringUtils.applyRelativePath(baseLocation, location), actualResources);
}
} catch (IOException ex) {
getReaderContext().error("Failed to resolve current resource location", ele, ex);
} catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]", ele, ex);
}
}
// 解析后进行监听器激活处理
Resource[] actResArray = actualResources.toArray(new Resource[0]);
getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
}
}
2.3.4 解析beans标签
对于嵌入式beans标签来说, 与单独的配置文件并没有太大的区别, 在DefaultBeanDefinitionDocumentReader的parseDefaultElement方法中就是直接调用doRegisterBeanDefinitions(ele), 递归调用beans的解析过程, 此处不再赘述.
2.4 解析自定义标签
默认标签解析完成之后, 接下来就开始分析自定义标签的处理过程了. 在分析代码之前先看下如何使用自定义标签, 大致可以分为以下几个步骤:
- 创建一个需要扩展的组件
- 定义一个XSD文件描述组件内容
- 创建BeanDefinitionParser的子类(一般继承AbstractSingleBeanDefinitionParser), 用来解析XSD文件中的定义和组件定义.
- 创建NamespaceHandler的子类(一般继承NamespaceHandlerSupport), 目的是将组件注册到Spring容器中.
- 编写Spring.handlers和Spring.schemas文件
现在回到DefaultBeanDefinitionDocumentReader的parseBeanDefinitions方法内, 当遇到XML中非默认标签时, 会调用delegate.parseCustomElement(ele)这行代码, 我们从这里开始分析.
public class BeanDefinitionParserDelegate {
@Nullable
public BeanDefinition parseCustomElement(Element ele) {
return parseCustomElement(ele, null);
}
@Nullable
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
// 获取对应的命名空间
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
// 根据命名空间找到对应的NamespaceHandler
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
}
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
public XmlReaderContext createReaderContext(Resource resource) {
return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
this.sourceExtractor, this, getNamespaceHandlerResolver());
}
public NamespaceHandlerResolver getNamespaceHandlerResolver() {
if (this.namespaceHandlerResolver == null) {
this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();
}
return this.namespaceHandlerResolver;
}
protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {
ClassLoader cl = (getResourceLoader() != null ? getResourceLoader().getClassLoader() : getBeanClassLoader());
return new DefaultNamespaceHandlerResolver(cl);
}
}
上述代码中, 通过标签的命名空间然后获取NamespaceHandler. 在XmlReaderContext初始化的时候, namespaceHandlerResolver属性已经初始化为DefaultNamespaceHandlerResolver, 在分析resolve方法前, 先了解下Spring.handlers中的内容.
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
上述内容截取自spring-context.jar的spring.handlers文件中, 其实就是一个properties文件, 记录了命名空间与处理器之间的映射关系, 其中namespace为key, NamespaceHandler处理器为value.
2.4.1 NamespaceHandler
public class DefaultNamespaceHandlerResolver implements NamespaceHandlerResolver {
public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";
private final String handlerMappingsLocation;
private volatile Map<String, Object> handlerMappings;
public DefaultNamespaceHandlerResolver() {
this(null, DEFAULT_HANDLER_MAPPINGS_LOCATION);
}
public DefaultNamespaceHandlerResolver(@Nullable ClassLoader classLoader) {
this(classLoader, DEFAULT_HANDLER_MAPPINGS_LOCATION);
}
public NamespaceHandler resolve(String namespaceUri) {
// 获取所有已经配置的handler映射
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;
try {
// 使用反射转化为Class对象, 并且实例化
Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri + "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
}
NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
namespaceHandler.init(); // 初始化方法
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;
} catch (ClassNotFoundException ex) {
throw new FatalBeanException("Could not find NamespaceHandler class [" + className +
"] for namespace [" + namespaceUri + "]", ex);
} catch (LinkageError err) {
throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
className + "] for namespace [" + namespaceUri + "]", err);
}
}
}
// 读取Spring.handlers配置文件并将配置文件缓存在map中
private Map<String, Object> getHandlerMappings() {
Map<String, Object> handlerMappings = this.handlerMappings;
if (handlerMappings == null) {
synchronized (this) {
handlerMappings = this.handlerMappings;
if (handlerMappings == null) {
try {
// 读取文件填充到Properties中
Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
handlerMappings = new ConcurrentHashMap<>(mappings.size());
CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings); // 合并
this.handlerMappings = handlerMappings;
} catch (IOException ex) {
throw new IllegalStateException("Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
}
}
}
}
return handlerMappings;
}
}
DefaultNamespaceHandlerResolver中的代码比较简单: 文件中读取内容, 根据类名反射并实例化NamespaceHandler. 之后调用其init方法, 注册一个或多个BeanDefinitionParser的实现类, 用于解析标签.
2.4.2 标签解析
回到BeanDefinitionParserDelegate的parseCustomElement方法中, 获取到NamespaceHandler之后, Spring调用NamespaceHandler的parse方法, 将解析的工作委托给了自定义的解析器去解析. 这里我们分析下NamespaceHandlerSupport中的parse方法.
public abstract class NamespaceHandlerSupport implements NamespaceHandler {
private final Map<String, BeanDefinitionParser> parsers = new HashMap<>();
// 自定义的NamespaceHandler中init方法中一般都会调用该方法注册BeanDefinitionParser
protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
this.parsers.put(elementName, parser);
}
public BeanDefinition parse(Element element, ParserContext parserContext) {
// 寻找解析器进行解析
BeanDefinitionParser parser = findParserForElement(element, parserContext);
return (parser != null ? parser.parse(element, parserContext) : null);
}
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
// 获取元素名称, 比如<context:component-scan />中的component-scan
String localName = parserContext.getDelegate().getLocalName(element);
// 根据component-scan找到对应的解析器
BeanDefinitionParser parser = this.parsers.get(localName);
if (parser == null) {
parserContext.getReaderContext().fatal("Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
}
return parser;
}
}
在我们自定义的NamespaceHandler中init的方法内, 一般会调用registerBeanDefinitionParser方法注册一个或多个BeanDefinitionParser, 比如在Spring中解析<context:component-scan />时使用的ContextNamespaceHandler类.
public class ContextNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
}
}
所以在findParserForElement时, 可以根据标签名找到对应的BeanDefinitionParser, Spring将标签的解析工作继续委托给了BeanDefinitionParser处理.
public abstract class AbstractBeanDefinitionParser implements BeanDefinitionParser {
public static final String ID_ATTRIBUTE = "id";
public static final String NAME_ATTRIBUTE = "name";
// 虽说parse方法是对自定义配置文件的解析, 但是这个函数大部分代码是用来处理解析后的AbstractBeanDefinition,
// 真正做解析的方法还是委托给了需要子类实现的parseInternal方法.
public final BeanDefinition parse(Element element, ParserContext parserContext) {
AbstractBeanDefinition definition = parseInternal(element, parserContext);
if (definition != null && !parserContext.isNested()) {
try {
String id = resolveId(element, definition, parserContext);
if (!StringUtils.hasText(id)) {
parserContext.getReaderContext().error(...);
}
String[] aliases = null;
if (shouldParseNameAsAliases()) {
String name = element.getAttribute(NAME_ATTRIBUTE);
if (StringUtils.hasLength(name)) {
aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
}
}
// 将AbstractBeanDefinition转换为BeanDefinitionHolder并注册
BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
registerBeanDefinition(holder, parserContext.getRegistry());
if (shouldFireEvents()) { // 是否需要通知监听器进行处理
BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
postProcessComponentDefinition(componentDefinition);
parserContext.registerComponent(componentDefinition);
}
} catch (BeanDefinitionStoreException ex) {
String msg = ex.getMessage();
parserContext.getReaderContext().error((msg != null ? msg : ex.toString()), element);
return null;
}
}
return definition;
}
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) throws BeanDefinitionStoreException {
if (shouldGenerateId()) {
return parserContext.getReaderContext().generateBeanName(definition);
} else {
String id = element.getAttribute(ID_ATTRIBUTE);
if (!StringUtils.hasText(id) && shouldGenerateIdAsFallback()) {
id = parserContext.getReaderContext().generateBeanName(definition);
}
return id;
}
}
protected abstract AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext);
}
public abstract class AbstractSingleBeanDefinitionParser extends AbstractBeanDefinitionParser {
// 在parseInternal中并不是直接调用doParse方法, 而是进行一系列的数据准备, 包括beanClass、scope等等
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
String parentName = getParentName(element);
if (parentName != null) {
builder.getRawBeanDefinition().setParentName(parentName);
}
// 获取自定义标签中的class属性, 子类可以覆盖getBeanClass或者getBeanClassName方法进行设定class属性
Class<?> beanClass = getBeanClass(element);
if (beanClass != null) {
builder.getRawBeanDefinition().setBeanClass(beanClass);
} else {
String beanClassName = getBeanClassName(element);
if (beanClassName != null) {
builder.getRawBeanDefinition().setBeanClassName(beanClassName);
}
}
builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
BeanDefinition containingBd = parserContext.getContainingBeanDefinition();
if (containingBd != null) {
// 若存在父类, 使用父类的scope属性
builder.setScope(containingBd.getScope());
}
if (parserContext.isDefaultLazyInit()) {
// 配置延迟加载
builder.setLazyInit(true);
}
// 调用子类的doParse方法进行解析
doParse(element, parserContext, builder);
return builder.getBeanDefinition();
}
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
doParse(element, builder);
}
protected void doParse(Element element, BeanDefinitionBuilder builder) {}
}
以上就是自定义标签的解析. 在自定义的BeanDefinitionParser中, 如果继承自AbstractSingleBeanDefinitionParser, 只需要在doParse方法中实现与自己业务逻辑相关的部分即可. 创建BeanDefinition以及进行相应默认属性的设置, 对于这些工作Spring都已经帮我们实现了, 只是暴露了一些接口来供用户实现个性化的业务.
3. 总结
以上就是本文的所有内容了, 以XmlBeanFactory为入口, 分析了Spring如何解析XML配置, 包括默认标签和自定义标签. 后续的文章会继续分析在Spring中如何加载bean. bean的加载会比XML的解析更加的复杂, 也需要更多的时间去理解.
浙公网安备 33010602011771号