曹工说Spring Boot源码(9)-- Spring解析xml文件,到底从中得到了什么(context命名空间上) (3)

这里,我们发现这个bean class,竟然是一个BeanFactoryPostProcessor。这个接口有什么作用呢,大概就是,等所有的beanDefinition都装载了之后,会调用实现了BeanFactoryPostProcessor接口的bean,对beanDefinition进行处理。

如果对这块感兴趣,可以看博主之前的一篇文章,网上也很多解析,可自行搜索:

曹工杂谈:为什么很少需要改Spring源码,因为扩展点太多了,说说Spring的后置处理器

context:property-override 用法

这个元素,一般比较少用,但今天查了一下,我觉得这个还比较有意思,而且很奇妙地和当前spring boot外部化配置的思想吻合。

它的用途说起来比较晦涩,我们看例子就知道了:

<?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 "> <bean > <property value="Ram"/> <property value="20"/> <property value="Varanasi"/> </bean> </beans> package org.springframework.contextnamespace; import lombok.Data; @Data public class Person { private String name; private int age; private String location; }

测试代码:

package org.springframework.contextnamespace; import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.util.MyFastJson; import java.util.List; import java.util.Map; /** * desc: * * @author : caokunliang * creat_date: 2019/12/25 0025 * creat_time: 15:50 **/ @Slf4j public class TestPropertyOverride { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( new String[]{"classpath:context-namespace-test-property-override.xml"},false); context.refresh(); // 获取bean Object bean = context.getBean(Person.class); System.out.println("bean:" + bean); } }

输出如下:

bean:Person(name=Ram, age=20, location=Varanasi)

这个应该大家都懂。

接下来,我们在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 "> // 配置了这个玩意 <context:property-override location="classpath:beanOverride.properties"/> <bean > <property value="Ram"/> <property value="20"/> <property value="Varanasi"/> </bean> </beans> #beanOverride.properties person.age=40 person.location=Delhi

测试程序不变,这次的输出如下:

bean:Person(name=Ram, age=40, location=Delhi)

也就是说,外部配置文件:beanOverride.properties中的属性,覆盖了xml中的bean的属性。

而现在,spring boot的environment解析变量时,也是外部的配置文件、命令行参数、环境变量等,优先级高于jar包内的配置,是不是和我们这个元素的作用比较像呢?

等价用法

如果不使用:,也可以像下面这样使用:

<bean> <property value="classpath:beanOverride.properties" /> </bean> 元素解析

从ContextNamespaceHandler,我们可以找到该元素对应的parser:PropertyOverrideBeanDefinitionParser

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()); }

类实现也很简单,和前面的一样,都继承了同一个基类:AbstractPropertyLoadingBeanDefinitionParser。

简单看看其实现吧:

class PropertyOverrideBeanDefinitionParser extends AbstractPropertyLoadingBeanDefinitionParser { @Override protected Class getBeanClass(Element element) { return PropertyOverrideConfigurer.class; } @Override protected void doParse(Element element, BeanDefinitionBuilder builder) { super.doParse(element, builder); builder.addPropertyValue("ignoreInvalidKeys", Boolean.valueOf(element.getAttribute("ignore-unresolvable"))); } }

这里,看看我们获得的bean class:

曹工说Spring Boot源码(9)-- Spring解析xml文件,到底从中得到了什么(context命名空间上)

和前面讨论的一样,也是一个BeanFactoryPostProcessor。

总结

又需要回答题目的问题了,从xml文件里,解析得到了什么呢,答案依然是beanDefinition。

不过呢,这次的beanClass,略有不同,因为他们是特殊的class,是可以参与beanDefinition生命周期的class,

因为他们实现了BeanFactoryPostProcessor。

大家可以再看看前面util命名空间,那些bean class呢,主要就是FactoryBean。

本篇源码位置:

https://gitee.com/ckl111/spring-boot-first-version-learn/tree/master/all-demo-in-spring-learning/spring-xml-demo/src/main/java/org/springframework/contextnamespace

由于context命名空间都是些大人物,所以本篇主要是先给大家热身,下一讲,我们讲讲这里面的:

annotation-config、component-scan

我简单看了两眼,还挺有意思,欢迎大家和我一起学习。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpdssz.html