前文 推测,Spring 提供一个标准(接口),其允许将不同形式的配置信息(不同格式的文件甚至可能时流等)解析为一个个的 Bean 定义信息(BeanDefinition) ,以供后续实例化使用。
结合Spring源码,本文将对BeanDefinitionReader接口与BeanDefinition接口进行验证。
准备代码:
public class SimpleXmlSpringStarter {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("application-context.xml");
Person bean = ctx.getBean(Person.class);
System.out.println(bean);
}
}
@Data
class Person{
private String name;
private String gender;
public void init(){
System.out.println("this is an init method");
}
}
-------- 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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="processing.Person">
<property name="name" value="what"/>
<property name="gender" value="seee"/>
</bean>
</beans>
以调试模式启动工程:
启动流程:
new ClassPathXmlApplicationContext()
》 调用父类构造方法:new AbstractApplicationContext(),初始化信息
public AbstractApplicationContext() {
this.logger = LogFactory.getLog(this.getClass());
this.id = ObjectUtils.identityToString(this);
this.displayName = ObjectUtils.identityToString(this);
this.beanFactoryPostProcessors = new ArrayList(); // BeanFactoryPostProcessor 集合,证明上文中推测的 BeanFactoryPostProcessor 存在,至于是否是对应的功能,后文验证
this.active = new AtomicBoolean();
this.closed = new AtomicBoolean();
this.startupShutdownMonitor = new Object(); // 初始化了一个开始关闭监控器,不知道什么作用,后文再看
this.applicationStartup = ApplicationStartup.DEFAULT;
this.applicationListeners = new LinkedHashSet(); // 初始化一个监听器集合,证明上文我们忽略了Spring 中监听器的问题,既然有监听器,那应该就有监听的事件存在,后文分析
this.resourcePatternResolver = this.getResourcePatternResolver(); // 不知道什么东西,后文再看
}
》 设置配置路径:
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
super(parent);
// 见名知义,设置配置路径,将用户传入的配置路径信息存入一个配置信息路径数组中
this.setConfigLocations(configLocations);
if (refresh) {
this.refresh();
}
}
public abstract class AbstractRefreshableConfigApplicationContext extends AbstractRefreshableApplicationContext
implements BeanNameAware, InitializingBean {
// 配置信息路径数组
@Nullable
private String[] configLocations;
// ....
}
》 调用刷新容器方法(refresh)
@Override
public void refresh() throws BeansException, IllegalStateException {
// 出现容器开启关闭监视器,其使用方式表明该监视器是个锁对象,
synchronized (this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
// 准备刷新spring 容器
// Prepare this context for refreshing.
prepareRefresh();
// 通知子类,刷新内部 Bean工厂
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
// ...
}
进入prepareRefresh 方法,开始准备刷新容器:
protected void prepareRefresh() {
// Switch to active.
this.startupDate = System.currentTimeMillis();
this.closed.set(false); // 设置关闭状态为 false
this.active.set(true); // 设置激活状态为 true
if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
}
else {
logger.debug("Refreshing " + getDisplayName());
}
}
// 在容器环境中初始化任意占位符属性资源,spring 中为空的模板方法,用于其他应用扩展
// Initialize any placeholder property sources in the context environment.
initPropertySources();
// 初始化容器环境,如果没有容器环境就实例化一个标准的容器环境 new StandardEnvironment();
// Validate that all properties marked as required are resolvable:
// 验证所有标记为必须的属性是否存在
// see ConfigurablePropertyResolver#setRequiredProperties
// 我们可以继承并重写此方法,并设置我们认为程序启动所必须的一些属性
getEnvironment().validateRequiredProperties();
// 表明 Spring 或者其扩展可能在完成某些功能之前就可能实例化出监听器
// Store pre-refresh ApplicationListeners...
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// Reset local application listeners to pre-refresh state.
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<>();
}
可以看到此方法主要负责:
设置标志位(容器关闭、开启状态标志位),初始化属性资源,初始化一个容器环境,并验证必须的属性,创建一个监听器集合与早期事件集合。
下一步:获得一个可配置的可列表化的Bean工厂,ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
return getBeanFactory();
}
@Override
protected final void refreshBeanFactory() throws BeansException {
// 如果有Bean工厂,摧毁并关闭 Bean 工厂
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 创建一个新的Bean工厂
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
// 个性化 Bean 工厂
customizeBeanFactory(beanFactory);
// 加载Bean定义信息!!!!!!!!!!!!!!!!!!!!!
// 注意: 我们即将要验证我们的关于BeanDefinitionReader与BeanDefinition 相关接口的推论
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
此方法中,关键点:createBeanFactory() 创建一个新的 Bean工厂,其内部通过 new 来实例化一个 Bean 工厂,个性化Bean工厂,与加载BeanDefinition(我们要验证的内容)。
先别急,先看个性化Bean工厂干了什么事儿:
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
// 允许 Bean 定义信息覆盖(所以可能会出现Bean定义信息的继承)
if (this.allowBeanDefinitionOverriding != null) {
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// 允许 循环依赖(关于循环依赖的问题出现了)
if (this.allowCircularReferences != null) {
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
}
现在来看我们的G点:加载BeanDefinition
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
// 创建一个新的 Xml的Bean定义信息读取器,那么可能还有其他类型的Bean定义信息读取器
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
// 设置环境
beanDefinitionReader.setEnvironment(this.getEnvironment());
// 设置资源加载器
beanDefinitionReader.setResourceLoader(this);
// 设置实体处理器,不知道干啥的,后面再看
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// 注释翻译:允许子类提供读取器自定义初始化信息
// Allow a subclass to provide custom initialization of the reader,
// 然后再加载Bean定义信息
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
发现出现我们前文推论中推论的 BeanDefinitionReader ,获取其类图:
接口方法:
public interface BeanDefinitionReader {
// Bean 定义信息注册器
BeanDefinitionRegistry getRegistry();
@Nullable
ResourceLoader getResourceLoader();
@Nullable
ClassLoader getBeanClassLoader();
// Bean 名称生成器
BeanNameGenerator getBeanNameGenerator();
// 加载Bean定义信息
int loadBeanDefinitions(Resource var1) throws BeanDefinitionStoreException;
int loadBeanDefinitions(Resource... var1) throws BeanDefinitionStoreException;
// 加载Bean定义信息
int loadBeanDefinitions(String var1) throws BeanDefinitionStoreException;
int loadBeanDefinitions(String... var1) throws BeanDefinitionStoreException;
}
出现了一个 Bean定义信息注册器,且提供了四种加载Bean定义信息的方法,注册器是什么先不管,先看,应该是后面四种方法来加载各种配置文件中的Bean定义信息。
在XmlBeanDefinitionReader 中,加载Bean定义信息方法中最终调用了方法:
public int loadBeanDefinitions(InputSource inputSource, @Nullable String resourceDescription) throws BeanDefinitionStoreException {
return this.doLoadBeanDefinitions(inputSource, new DescriptiveResource(resourceDescription));
}
表明其将 xml 文档转换为输入流,并交由 doLoadBeanDefinitions 方法真正加载(那我们是不是可以写一个扩展 JsonBeanDefinitionReader 来支持以 Json 方式定义 Bean )
(到此,我们已经验证了我们前文关于 BeanDefinitionReader 的相关推论了!)
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
try {
// 加载 xml文档,
Document doc = this.doLoadDocument(inputSource, resource);
// 注册xml文档中Bean 定义信息
int count = this.registerBeanDefinitions(doc, resource);
return count;
} catch (Throwable var10) {
// ...
}
}
关键点:int count = this.registerBeanDefinitions(doc, resource), 来看看它干了什么:
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// 创建一个 Bean 定义文档读取器
BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();
// 取出Bean定义注册器中现有的Bean定义信息数量
int countBefore = this.getRegistry().getBeanDefinitionCount();
// 关键方法: 注册Bean定义信息
documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));
// 计算本次加载的Bean定义信息数量信息
return this.getRegistry().getBeanDefinitionCount() - countBefore;
}
在:documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource)) 中,debug 跟踪源代码,发现其最终调用了以下
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 处理 xml 元素,并返回一个Bean 定义信息持有器
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 将持有其注册到Bean 定义信息注册器中
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
} catch (BeanDefinitionStoreException var5) {
this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
}
this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
方法: BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele) 中,调用了一下内容:
public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
// 获取类名
String className = null;
if (ele.hasAttribute("class")) {
className = ele.getAttribute("class").trim();
}
String parent = null;
if (ele.hasAttribute("parent")) {
parent = ele.getAttribute("parent");
}
try {
// 创建 Bean 定义信息
AbstractBeanDefinition bd = this.createBeanDefinition(className, parent);
// 处理相关属性
this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
// ....
AbstractBeanDefinition var7 = bd;
return var7;
// ....
} catch (Throwable var15) {
// ....
} finally {
// ....
}
return null;
}
方法: BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
// 获取 Bean 名称
String beanName = definitionHolder.getBeanName();
// 注册 Bean 定义信息
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
String[] var4 = aliases;
int var5 = aliases.length;
for(int var6 = 0; var6 < var5; ++var6) {
String alias = var4[var6];
registry.registerAlias(beanName, alias);
}
}
}
方法: definitionHolder.getBeanDefinition() 为 BeanDefinitionHolder 成员变量 BeanDefintion 的get方法,自持 上文关于 BeanDefinition 的推论证实。( BeanDefinition 在其他地方已经出现,因为在跟代码的过程中有一些流程忽略,才到这里)
到此,我们已证实我们在上文中关于 BeanDefinitionReader与BeanDefinition的推论,其实只要证实BeanDefinitionReader 就已经证实了关于BeanDefinition的推论了。
下文,我们将继续验证我们关于 BeanFactoryPostProcessor 的推论!