初探Spring 源码记实——Bean实例化流程推测验证之:BeanDefinition接口 / BeanDefinitionReader 接口

        前文 推测,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 的推论!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Asial Jim

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值