2021-08-25 SpringBean实例化源码解析

首先Spring通过读取XML由多方面解析.
1.Application上下文、
2.解析XML、
3.Application上下文消息总线传播进行通知,进行事件触发,从开启容器到关闭容器通过Spring发布消息总线通知上下文该怎样进行一个操作。
4、Spring的刷新机制
5、Spring实例化Bean进行装配

下面我们通过跟踪源码来进行解析

package org.springframework.bean;

/**
 * @author pm
 * @apiNode MyBean
 * @date 2021/8/2217:48
  * 稍后要进行实例化的Bean 自定义类
 */
public class MyBean {
}

配置文件

<?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="MyBean" class="org.springframework.bean.MyBean"></bean>
<!--    <bean name="HelloWorld" class="org.springframework.publish.HelloWorld">-->
<!--        <property name="msg" value="hhhhh"></property>-->
<!--    </bean>-->

<!--    <bean name= "eventReceiver"   class = "org.springframework.publish.EventReceiver" />-->
</beans>

启动类

package org.springframework.main;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.publish.HelloWorld;

/**
 * @author pm
 * @apiNode App
 * @date 2021/8/2217:49
 */
public class App {
      //这里我们是通过ClassPathXmlApplicationContext这个类来解析XML配置文件来装配Bean进行实例化
    //首先会进入ClassPathXmlApplicationContext的默认构造函数
    public static void main(String[] args) {
        BeanFactory bean = new ClassPathXmlApplicationContext("bean.xml");
        System.out.println(bean.getBean("MyBean"));
//      HelloWorld helloWorld = (HelloWorld) bean.getBean("HelloWorld");
//      helloWorld.send();
    }
}

下面我们进行跟踪 来到了ClassPathXmlApplicationContext

首先我们进入了第一个断点,通过传入的bean.xml进行读取,我们看到该方法有几个关键参数
1、configLocation 传入的是bean.xml 显而易见后续会通过该方法进行解析
2、refresh 是否对上下文进行刷新,后续会讲到,这里能理解到,当我们要进行Bean实例化之前会进行刷新一次
3、parent 这个参数表示,是否有父级容器,在Spring加载时通过配置文件解析,再通过Application上下文通知会有两个容器产生,一个父容器,一个子容器,当我们只进行单纯的对象装配时,他不会使用到父容器,而是使用子容器。
这里通过this调用了本身的构造函数


image.png
image.png

在ClassPathXmlApplicationContext 类有参构造函数中我们发现他通过构造函数这里调用了两个方法
1、setConfigLocations 传入的是配置文件信息
2、刷新上下文机制

下面我们点进去看看这个setConfigLocations 其中会对路径 占位符 等进行解析然后返回一个xml


image.png

然后我们进入刷新上下文方法看做了什么,这里start方法进行上下文初始化,
他返回的是一个StartupStep类,我们打开该类里面描述了一个上下文的生命周期,通过调用start方法FlightRecorderStartupStep类实现了该方法,返回了上下文启动的操作记录


image.png

然后我们往下走,进入了prepareRefresh()方法


image.png

在该方法中进行了设置上下文相关属性以及解析XML,发布Spring消息源的预处理

/**
     * Prepare this context for refreshing, setting its startup date and
     * active flag as well as performing any initialization of property sources.
     */
    protected void prepareRefresh() {
        // Switch to active.
        //上下文启动时间
        this.startupDate = System.currentTimeMillis();
        //是否关闭上下文
        this.closed.set(false);
        //上下文是否处于活动状态
        this.active.set(true);

        if (logger.isDebugEnabled()) {
            if (logger.isTraceEnabled()) {
                logger.trace("Refreshing " + this);
            }
            else {
                logger.debug("Refreshing " + getDisplayName());
            }
        }
        //资源初始化
        // Initialize any placeholder property sources in the context environment.
        initPropertySources();

        //验证XML
        // Validate that all properties marked as required are resolvable:
        // see ConfigurablePropertyResolver#setRequiredProperties
        getEnvironment().validateRequiredProperties();

        //存储预刷新应用程序侦听器。。。
        // 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);
        }
        //允许收集早期ApplicationEvents,
        // Allow for the collection of early ApplicationEvents,
        //将在Multicast可用后发布。。。
        //预发布上下文事件
        // to be published once the multicaster is available...
        this.earlyApplicationEvents = new LinkedHashSet<>();
    }

往下走


image.png

这里通过该方法会引用到AbstractXmlApplicationContext类的loadBeanDefinitions


image.png

可以看到已经生成了一个序列化ID,然后生成新的上下文环境,返回一个新的消息对象总之,在该方法中加载资源并且装配Bean,然后通过计数器进行计数


image.png

装配Bean,并且刷新,刷新后会经历清除缓存的一系列操作后生成Bean,返回消息对象

这里调用了prepareBeanFactory 方法传入的是刚刚的读取的Bean实例


image.png
/**
     * Configure the factory's standard context characteristics,
     * such as the context's ClassLoader and post-processors.
     * @param beanFactory the BeanFactory to configure
     */
    protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // Tell the internal bean factory to use the context's class loader etc.
        //设置Bean的类加载器
        beanFactory.setBeanClassLoader(getClassLoader());
        if (!shouldIgnoreSpel) {
            //解析Bean类名并进行返回 进行表达式解析
            beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
        }
        //解析Bean上下文并解析注册
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

        // Configure the bean factory with context callbacks.
        //上下文解析器
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
        //环境配置
        beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
        //嵌入值解析
        beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
        //加载资源
        beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
        //用于发布消息总线设置上下文
        beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
        //消息资源
        beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
        //设置Application上下文
        beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
        //启动上下文对象
        beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);

        // BeanFactory interface not registered as resolvable type in a plain factory.
        // MessageSource registered (and found for autowiring) as a bean.
        //自动装配
        beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
        //资源加载器
        beanFactory.registerResolvableDependency(ResourceLoader.class, this);
        //发布消息总线
        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
        //上下文对象
        beanFactory.registerResolvableDependency(ApplicationContext.class, this);
        //加载上下文的Bean监听器
        // Register early post-processor for detecting inner beans as ApplicationListeners.
        beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

        // Detect a LoadTimeWeaver and prepare for weaving, if found.
        if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            //为类型匹配设置临时类加载器。
            // Set a temporary ClassLoader for type matching.
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }

        //注册默认环境bean。
        // Register default environment beans.
        if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
            beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
        }
        if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
            beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
        }
        if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
            beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
        }
        if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
            beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
        }
    }
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容