spring解析配置文件

Posted zhenhong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring解析配置文件相关的知识,希望对你有一定的参考价值。

一、从XmlBeanDefinitionReader的registerBeanDefinitions(doc,resource)开始

1 protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
2             throws BeanDefinitionStoreException {
3         try {
4             Document doc = doLoadDocument(inputSource, resource);
5             return registerBeanDefinitions(doc, resource);
6         }

进入第5行的registerBeanDefinitions方法

1 public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
2         BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
3         int countBefore = getRegistry().getBeanDefinitionCount();
4         documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
5         return getRegistry().getBeanDefinitionCount() - countBefore;
6     }

第二行创建了一个bean定义文档阅读器,创建的代码如下,第三行的getRegistry()方法得到是DefaultListableBeanFactory类的实例,是个bean工厂,这个工厂在准备读取xml时创建xml阅读器的时候就已经设置进去,getBeanDefinitions方法里的代码就这一句this.beanDefinitionMap.size(),获取bean定义容器的大小,很显然对于我这里是没有的,因为还没解析xml。

1 protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
2         return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
3     }

在看看第4行的documentReader.registerBeanDefinitions这个方法

1 @Override
2     public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
3         this.readerContext = readerContext;
4         logger.debug("Loading bean definitions");
5         Element root = doc.getDocumentElement();
6         doRegisterBeanDefinitions(root);
7     }

第5行获得了xml的根元素<beans>然后调用

doRegisterBeanDefinitions方法,并把根元素传入进入

 1 protected void doRegisterBeanDefinitions(Element root) {
 2         // Any nested <beans> elements will cause recursion in this method. In
 3         // order to propagate and preserve <beans> default-* attributes correctly,
 4         // keep track of the current (parent) delegate, which may be null. Create
 5         // the new (child) delegate with a reference to the parent for fallback purposes,
 6         // then ultimately reset this.delegate back to its original (parent) reference.
 7         // this behavior emulates a stack of delegates without actually necessitating one.
 8         BeanDefinitionParserDelegate parent = this.delegate;
 9         this.delegate = createDelegate(getReaderContext(), root, parent);
10 
11         if (this.delegate.isDefaultNamespace(root)) {
12             String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
13             if (StringUtils.hasText(profileSpec)) {
14                 String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
15                         profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
16                 if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
17                     return;
18                 }
19             }
20         }
21 
22         preProcessXml(root);
23         parseBeanDefinitions(root, this.delegate);
24         postProcessXml(root);
25 
26         this.delegate = parent;
27     }
第9行创建了使用createDelegate方法创建了一个BeanDefinitionParserDelegate类的实例,它内部的代码如下
1 protected BeanDefinitionParserDelegate createDelegate(
2             XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {
3 
4         BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
5         delegate.initDefaults(root, parentDelegate);
6         return delegate;
7     }

第4行的readerContext是一个XMLReaderContext,继续往下调用了initDefaults方法,初始化默认值

1 public void initDefaults(Element root, BeanDefinitionParserDelegate parent) {
2         populateDefaults(this.defaults, (parent != null ? parent.defaults : null), root);
3         this.readerContext.fireDefaultsRegistered(this.defaults);
4     }

进入populateDefaults方法

 1 protected void populateDefaults(DocumentDefaultsDefinition defaults, DocumentDefaultsDefinition parentDefaults, Element root) {
 2         String lazyInit = root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE);
 3         if (DEFAULT_VALUE.equals(lazyInit)) {
 4             // Potentially inherited from outer <beans> sections, otherwise falling back to false.
 5             lazyInit = (parentDefaults != null ? parentDefaults.getLazyInit() : FALSE_VALUE);
 6         }
 7         defaults.setLazyInit(lazyInit);
 8 
 9         String merge = root.getAttribute(DEFAULT_MERGE_ATTRIBUTE);
10         if (DEFAULT_VALUE.equals(merge)) {
11             // Potentially inherited from outer <beans> sections, otherwise falling back to false.
12             merge = (parentDefaults != null ? parentDefaults.getMerge() : FALSE_VALUE);
13         }
14         defaults.setMerge(merge);
15 
16         String autowire = root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE);
17         if (DEFAULT_VALUE.equals(autowire)) {
18             // Potentially inherited from outer <beans> sections, otherwise falling back to \'no\'.
19             autowire = (parentDefaults != null ? parentDefaults.getAutowire() : AUTOWIRE_NO_VALUE);
20         }
21         defaults.setAutowire(autowire);
22 
23         // Don\'t fall back to parentDefaults for dependency-check as it\'s no longer supported in
24         // <beans> as of 3.0. Therefore, no nested <beans> would ever need to fall back to it.
25         defaults.setDependencyCheck(root.getAttribute(DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE));
26 
27         if (root.hasAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)) {
28             defaults.setAutowireCandidates(root.getAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE));
29         }
30         else if (parentDefaults != null) {
31             defaults.setAutowireCandidates(parentDefaults.getAutowireCandidates());
32         }
33 
34         if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) {
35             defaults.setInitMethod(root.getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE));
36         }
37         else if (parentDefaults != null) {
38             defaults.setInitMethod(parentDefaults.getInitMethod());
39         }
40 
41         if (root.hasAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)) {
42             defaults.setDestroyMethod(root.getAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE));
43         }
44         else if (parentDefaults != null) {
45             defaults.setDestroyMethod(parentDefaults.getDestroyMethod());
46         }
47 
48         defaults.setSource(this.readerContext.extractSource(root));
49     }

第2行的DEFAULT_LAZY_INIT_ATTRIBUTE的值是default-lazy-init,第7行设置懒加载,还有默认的初始化方法什么的,把这些个属性全都设置到

DocumentDefaultsDefinition 中。这个方法返回后继续调用了XmlReaderContext的fireDefaultsRegistered方法,不过里面啥都没做。

接下来有回到了
doRegisterBeanDefinitions方法
 1 protected void doRegisterBeanDefinitions(Element root) {
 2         // Any nested <beans> elements will cause recursion in this method. In
 3         // order to propagate and preserve <beans> default-* attributes correctly,
 4         // keep track of the current (parent) delegate, which may be null. Create
 5         // the new (child) delegate with a reference to the parent for fallback purposes,
 6         // then ultimately reset this.delegate back to its original (parent) reference.
 7         // this behavior emulates a stack of delegates without actually necessitating one.
 8         BeanDefinitionParserDelegate parent = this.delegate;
 9         this.delegate = createDelegate(getReaderContext(), root, parent);
10 
11         if (this.delegate.isDefaultNamespace(root)) {
12             String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
13             if (StringUtils.hasText(profileSpec)) {
14                 String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
15                         profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
16                 if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
17                     return;
18                 }
19             }
20         }
21 
22         preProcessXml(root);
23         parseBeanDefinitions(root, this.delegate);
24         postProcessXml(root);
25 
26         this.delegate = parent;
27     }

第11行判断当前的根元素是否是默认的命名空间,spring中存在着两种标签,一种是默认的标签,另一种是自定义标签

第12行获得profile属性,这个属性应用于对个beans标签的情况,从spring3开始的,这样我们可以写多套bean定义,特别是使用到数据源的时候,可以切换不同的数据源,想要使用哪个bean定义就激活谁,想详细了解的,可以去查查资料。

第22行是个空方法,里面什么也没做,这个地方可以进行扩展,在解析bean定义之前,可以先处理自定义的标签

第23行方法的代码如下

 1 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
 2         if (delegate.isDefaultNamespace(root)) {
 3             NodeList nl = root.getChildNodes();
 4             for (int i = 0; i < nl.getLength(); i++) {
 5                 Node node = nl.item(i);
 6                 if (node instanceof Element) {
 7                     Element ele = (Element) node;
 8                     if (delegate.isDefaultNamespace(ele)) {
 9                         parseDefaultElement(ele, delegate);
10                     }
11                     else {
12                         delegate.parseCustomElement(ele);
13                     }
14                 }
15             }
16         }
17         else {
18             delegate.parseCustomElement(root);
19         }
20     }

第2行判断root是否是默认的命名空间,第3行获得根元素下的子节点,循环遍历子节点,第8行判断每个子节点是否是默认的命名空间,如果是就执行parseDefaultElement方法,否则

执行parseCustomElement方法,什么是自定义的标签呢,比如用户自己实现的标签,还有就是spring的aop,tx这类标签都是有自定义的命名空间的标签

我们进到parseCustomElement方法中看看

1 public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
2         String namespaceUri = getNamespaceURI(ele);
3         NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
4         if (handler == null) {
5             error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
6             return null;
7         }
8         return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
9     }

第2行获取这个元素的命名空间,通过命名空间可以在类路径下的spring.handlers中找到对应的处理器,在spring.schemas中找到对应的xsd文件。进入resolve方法查看一下他的

代码逻辑

 1 @Override
 2     public NamespaceHandler resolve(String namespaceUri) {
 3         Map<String, Object> handlerMappings = getHandlerMappings();
 4         Object handlerOrClassName = handlerMappings.get(namespaceUri);
 5         if (handlerOrClassName == null) {
 6             return null;
 7         }
 8         else if (handlerOrClassName instanceof NamespaceHandler) {
 9             return (NamespaceHandler) handlerOrClassName;
10         }
11         else {
12             String className = (String) handlerOrClassName;
13             try {
14                 Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
15                 if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
16                     throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
17                             "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
18                 }
19                 NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
20                 namespaceHandler.init();
21                 handlerMappings.put(namespaceUri, namespaceHandler);
22                 return namespaceHandler;
23             }
24             catch (ClassNotFoundException ex) {
25                 throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" +
26                         namespaceUri + "] not found", ex);
27             }
28             catch (LinkageError err) {
29                 throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" +
30                         namespaceUri + "]: problem with handler class file or dependent class", err);
31             }
32         }
33     }

第3行代码getHandlerMappings()获得所有的命名空间和处理程序的映射

 1 private Map<String, Object> getHandlerMappings() {
 2         if (this.handlerMappings == null) {
 3             synchronized (this) {
 4                 if (this.handlerMappings == null) {
 5                     try {
 6                         Properties mappings =
 7                                 PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
 8                         if (logger.isDebugEnabled()) {
 9                             logger.debug("Loaded NamespaceHandler mappings: " + mappings);
10                         }
11                         Map<String, Object> handlerMappings = new ConcurrentHashMap<String, Object>(mappings.size());
12                         CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
13                         this.handlerMappings = handlerMappings;
14                     }
15                     catch (IOException ex) {
16                         throw new IllegalStateException(
17                                 "Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
18                     }
19                 }
20             }
21         }
22         return this.handlerMappings;
23     }

进入第7行看看

 1 public static Properties loadAllProperties(String resourceName, ClassLoader classLoader) throws IOException {
 2         Assert.notNull(resourceName, "Resource name must not be null");
 3         ClassLoader classLoaderToUse = classLoader;
 4         if (classLoaderToUse == null) {
 5             classLoaderToUse = ClassUtils.getDefaultClassLoader();
 6         }
 7         Enumeration<URL> urls = (classLoaderToUse != null ? classLoaderToUse.getResources(resourceName) :
 8                 ClassLoader.getSystemResources(resourceName));
 9         Properties props = new Properties();
10         while (urls.hasMoreElements()) {
11             URL url = urls.nextElement();
12             URLConnection con = url.openConnection();
13             ResourceUtils.useCachesIfNecessary(con);
14             InputStream is = con.getInputStream();
15             try {
16                 if (resourceName.endsWith(XML_FILE_EXTENSION)) {
17                     props.loadFromXML(is);
18                 }
19                 else {
20                     props.load(is);
21                 }
22             }
23             finally {
24                 is.close();
25             }
26         }
27         return props;
28     }

它是通过加载器加载classpath下的META-INF/spring.handler文件,使用jdk的Properties方法加载,加载完后返回properties的实例,最后拿到对应的标签处理器

 

 拿到命名空间处理器的类名后

1 NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
2                 namespaceHandler.init();
3                 handlerMappings.put(namespaceUri, namespaceHandler);
4                 return namespaceHandler;

第1行使用bean助手类实例化了这个命名空间处理器,并进行了初始化,加入我显示使用的是aop的命名空间,那么这个命名空间处理器是AopNamespaceHandler类的实例

它对应init方法代码如下:这个aop命名空间处理器中拥有下面这些类别的标签解析器,第一个我们是最属性的,这个解析器里提供了aop:config标签中pointcut,before之类的解析方法

第3行将初始化好的命名空间处理器放到handlerMappings中,如果下次要使用就直接可以拿到,不需要在此实例化

@Override
    public void init() {
        // In 2.0 XSD as well as in 2.1 XSD.
        registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
        registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
        registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());

        // Only in 2.0 XSD: moved to context namespace as of 2.1
        registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
    }

下面是一些bean定义解析器的继承结构,各种各样的解析器

 

向处理器中注册解析器
1 protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
2         this.parsers.put(elementName, parser);
3     }

第2行的parsers是一个Map,用来存放bean定义解析器

得到命名空间处理器后再调用命名空间处理器的parse方法handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));

进入parse方法,这个方法又调用了findParserForElement方法
1 private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
      
2 String localName = parserContext.getDelegate().getLocalName(element); 3 BeanDefinitionParser parser = this.parsers.get(localName); 4 if (parser == null) { 5 parserContext.getReaderContext().fatal( 6 "Cannot locate BeanDefinitionParser for element [" + localName + "]", element); 7 } 8 return parser; 9 }

第2行,通过这个元素拿到了它的本地名字,比如aop:config元素的本地名为config

通过config从命名空间中的解析器map容器中拿到了对应的解析器,然后调用这个aop的config解析器的parse方法

 1 @Override
 2     public BeanDefinition parse(Element element, ParserContext parserContext) {
 3         CompositeComponentDefinition compositeDef =
 4                 new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
 5         parserContext.pushContainingComponent(compositeDef);
 6 
 7         configureAutoProxyCreator(parserContext, element);
 8 
 9         List<Element> childElts = DomUtils.getChildElements(element);
10         for (Element elt: childElts) {
11             String localName = parserContext.getDelegate().getLocalName(elt);
12             if (POINTCUT.equals(localName)) {
13                 parsePointcut(elt, parserContext);
14             }
15             else if (ADVISOR.equals(localName)) {
16                 parseAdvisor(elt, parserContext);
17             }
18             else if (ASPECT.equals(localName)) {
19                 parseAspect(elt, parserContext);
20             }
21         }
22 
23         parserContext.popAndRegisterContainingComponent();
24         return null;
25     }

 

第三行创建了一个组件定义,并将它压入ParseContext上下文中的stack中

进入第7行的方法
1 private void configureAutoProxyCreator(ParserContext parserContext, Element element) {
2         AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
3     }

这个方法是在配置自动代理创建者,这个方法在配置了<aop:config>才使用,如果你配置的是<aop:aspect-autoproxy/>这个标签,就会使用AspectJAutoProxyBeanDefinitionParser这个类的解析器。回到aop:config这个标签的解析器,上面的第2行使用了AopNamespaceUtils aop命名空间助手类注册一个自动代理切面创建者,进入这个方法看看

1 public static void registerAspectJAutoProxyCreatorIfNecessary(
2             ParserContext parserContext, Element sourceElement) {
3 
4         BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
5                 parserContext.getRegistry(), parserContext.extractSource(sourceElement));
6         useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
7         registerComponentIfNecessary(beanDefinition, parserContext);
8     }

 

第4行调用了registerAspectJAutoProxyCreatorIfNecessary的重载方法,这个方法传入了BeanRegistry类的对象(这里的这个实例实际上是DefaultListableBeanFactory)和ParseContext包装后的可提取资源实例
进入这个方法查看一下它的代码
1 public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
2         return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
3     }

第2行传入了一个AspectJAwareAdvisorAutoProxyCreator.class类对象,暂且不管它是干啥的,继续往下看

 1 private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
 2         Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
 3         if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
 4             BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
 5             if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
 6                 int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
 7                 int requiredPriority = findPriorityForClass(cls);
 8                 if (currentPriority < requiredPriority) {
 9                     apcDefinition.setBeanClassName(cls.getName());
10                 }
11             }
12             return null;
13         }
14         RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
15         beanDefinition.setSource(source);
16         beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
17         beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
18         registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
19         return beanDefinition;
20     }

第3行判断这个BeanFactory中的BeanDefinitionMap容器中是否存在一个key叫做AUTO_PROXY_CREATOR_BEAN_NAME

(org.springframework.aop.config.internalAutoProxyCreator)的元素,如果存在就获得他的BeanDefinition对象,并且与我们传进来的AspectJAwareAdvisorAutoProxyCreator

类名是否一样,如果一样就要根据优先级来选择其中一个作为自动创建代理类,在AopConfigUtils类中有个静态的属性list集合APC_PRIORITY_LIST,

它在静态块中初始化

 1 private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<Class<?>>();
 2 
 3     /**
 4      * Setup the escalation list.
 5      */
 6     static {
 7         APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
 8         APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
以上是关于spring解析配置文件的主要内容,如果未能解决你的问题,请参考以下文章

Spring boot:thymeleaf 没有正确渲染片段

Spring源码解析之基础应用

Spring的配置文件ApplicationContext.xml配置头文件解析

spring实现文件上传(图片解析)

vscode 开发微信小程序环境配置

多个 Spring 配置文件的属性解析(yaml 配置)