• Spring IoC Container源码分析(二)-bean初始化流程


    准备

    Person实例

    @Data
    public class Person {
        private String name;
        private int age;
    }
    

    xml bean配置

    <?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
                            http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/context
                            http://www.springframework.org/schema/context/spring-context.xsd">
        <bean id="person" class="com.gcdd1993.spring.framework.base.domain.Person"/>
    </beans>
    

    入口

    AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext("config.xml");
    applicationContext.getBean("person");
    

    使用Debug进入ClassPathXmlApplicationContext构造函数,源码如下

    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {
    
        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();
        }
    }
    

    super(parent)

    一步步向上调用父类构造函数,路径为

    ClassPathXmlApplicationContext -> AbstractXmlApplicationContext -> AbstractRefreshableConfigApplicationContext -> AbstractRefreshableApplicationContext -> AbstractApplicationContext

    历经整个继承体系,最终到达AbstractApplicationContext:

    public AbstractApplicationContext(ApplicationContext parent) {
        this();
        setParent(parent);
    }
    

    最后会设置当前ApplicationContext的父级ApplicationContext

    setConfigLocations(configLocations)

    设置配置文件路径,解析的细节参照官方文档Resource一节,不是本文讨论的重点,在此略过。

    public void setConfigLocations(String... locations) {
        if (locations != null) {
            Assert.noNullElements(locations, "Config locations must not be null");
            this.configLocations = new String[locations.length];
            for (int i = 0; i < locations.length; i++) {
                this.configLocations[i] = resolvePath(locations[i]).trim();
            }
        }
        else {
            this.configLocations = null;
        }
    }
    

    refresh()

    此方法是Spring容器的核心方法,源码(精简了try catch部分)如下:

    public void refresh() throws BeansException, IllegalStateException {
        // Prepare this context for refreshing.
        prepareRefresh();
    
        // Tell the subclass to refresh the internal bean factory.
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
        // Prepare the bean factory for use in this context.
        prepareBeanFactory(beanFactory);
    
        // Allows post-processing of the bean factory in context subclasses.
        postProcessBeanFactory(beanFactory);
    
        // Invoke factory processors registered as beans in the context.
        invokeBeanFactoryPostProcessors(beanFactory);
    
        // Register bean processors that intercept bean creation.
        registerBeanPostProcessors(beanFactory);
    
        // Initialize message source for this context.
        initMessageSource();
    
        // Initialize event multicaster for this context.
        initApplicationEventMulticaster();
    
        // Initialize other special beans in specific context subclasses.
        onRefresh();
    
        // Check for listener beans and register them.
        registerListeners();
    
        // Instantiate all remaining (non-lazy-init) singletons.
        finishBeanFactoryInitialization(beanFactory);
    
        // Last step: publish corresponding event.
        finishRefresh();
    }
    

    此处可以看到Spring编码方式近似于流程图的,重点部分都抽出为了单独的方法,流程清晰,易于理解。我们一步步看:

    prepareRefresh()

    上下文刷新前预热

    protected void prepareRefresh() {
        this.startupDate = System.currentTimeMillis();
        this.closed.set(false);
        this.active.set(true);
    
        if (logger.isInfoEnabled()) {
            logger.info("Refreshing " + this);
        }
    
        // Initialize any placeholder property sources in the context environment
        initPropertySources();
    
        // Validate that all properties marked as required are resolvable
        // see ConfigurablePropertyResolver#setRequiredProperties
        getEnvironment().validateRequiredProperties();
    
        // Allow for the collection of early ApplicationEvents,
        // to be published once the multicaster is available...
        this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
    }
    
    1. 设置上下文基本信息,如startupDate(启动时刻)、closed(是否关闭)、active(是否存活)等等。
    2. 解析占位符资源,并验证标记为required的资源是否可用

    obtainFreshBeanFactory()

    初始化beanFactory(bean工厂,实际存放bean的就是它了)

    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        refreshBeanFactory();
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (logger.isDebugEnabled()) {
            logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
        }
        return beanFactory;
    }
    

    核心方法refreshBeanFactory()

    protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            customizeBeanFactory(beanFactory);
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }
    
    1. createBeanFactory();
    2. 设置beanFactory属性
    3. loadBeanDefinitions(beanFactory);

    loadBeanDefinitions(beanFactory)

    解析bean定义,有几个bean就有几个BeanDefinition。注意,Spring并不是拿到配置就直接用反射实例化bean,而是先将bean配置解析为BeanDefinition。

    BeanDefinition保存了实例化bean需要的一切信息,包括属性,依赖等。以ConcurrentHashMap<String, BeanDefinition>保存在DefaultListableBeanFactory的beanDefinitionMap里。

    prepareBeanFactory(beanFactory)

    设置beanFactory的其余属性

    postProcessBeanFactory(beanFactory)

    空实现,给子类一个机会,自定义beanFactory后置处理器

    BeanFactoryPostProcessor定义:

    public interface BeanFactoryPostProcessor {
    
        void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
    
    }
    

    invokeBeanFactoryPostProcessors(beanFactory)

    执行上一步中的beanFactory后置处理器的回调方法void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)

    registerBeanPostProcessors(beanFactory)

    注册bean后置处理器,实现bean初始化前后的自定义逻辑

    BeanPostProcessor定义:

    public interface BeanPostProcessor {
        // 在bean实例化前调用
        Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
        // 在bean实例化后调用
        Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
    }
    

    initMessageSource()

    注册国际化相关bean

    initApplicationEventMulticaster()

    初始化Spring事件发布相关bean

    onRefresh()

    空实现,给子类一个机会,初始化特殊bean

    registerListeners()

    注册监听器

    finishBeanFactoryInitialization(beanFactory)

    实例化所有非懒加载的bean

    直到这里,才开始真正实例化bean

    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        // 1. 实例化bean的类型转换器
        if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
                beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
            beanFactory.setConversionService(
                    beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
        }
    
        // 2. 实例化属性占位符解析器
        if (!beanFactory.hasEmbeddedValueResolver()) {
            beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
                @Override
                public String resolveStringValue(String strVal) {
                    return getEnvironment().resolvePlaceholders(strVal);
                }
            });
        }
    
        // 3. 实例化LoadTimeWeaverAware
        String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
        for (String weaverAwareName : weaverAwareNames) {
            getBean(weaverAwareName);
        }
    
        // 4. 停止使用临时ClassLoader进行类型匹配
        beanFactory.setTempClassLoader(null);
    
        // 5. 禁止再修改bean定义
        beanFactory.freezeConfiguration();
    
        // 6. 实例化所有非懒加载单例bean
        beanFactory.preInstantiateSingletons();
    }
    

    preInstantiateSingletons()

    1. 根据每一个bean定义,实例化bean
    2. 为每一个实现SmartInitializingSingleton的bean执行回调方法

    实例化bean部分的代码:

    for (String beanName : beanNames) {
        // 获取bean定义
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        // 只有不是abstract、单例且不是懒加载的bean才在这里实例化
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            // 如果是FactoryBean
            if (isFactoryBean(beanName)) {
                // 先实例化实例对应的FactoryBean
                final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
                boolean isEagerInit;
                if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                    isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
                        @Override
                        public Boolean run() {
                            return ((SmartFactoryBean<?>) factory).isEagerInit();
                        }
                    }, getAccessControlContext());
                }
                else {
                    isEagerInit = (factory instanceof SmartFactoryBean &&
                            ((SmartFactoryBean<?>) factory).isEagerInit());
                }
                if (isEagerInit) {
                    // 使用FactoryBean的getObject()方法返回真正的实例
                    getBean(beanName);
                }
            }
            else {
                getBean(beanName);
            }
        }
    }
    

    getBean(String name)

    该方法调用了一个doGetBean,doGetBean代码较长,而且有部分代码是为了解决并发场景下单例的生成,我们挑出重点的看:

    1. 从父BeanFactory检查是否存在该bean的定义,如果存在,委托父BeanFactory来实例化
    BeanFactory parentBeanFactory = getParentBeanFactory();
    if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
        // Not found -> check parent.
        String nameToLookup = originalBeanName(name);
        if (args != null) {
            // Delegation to parent with explicit args.
            return (T) parentBeanFactory.getBean(nameToLookup, args);
        }
        else {
            // No args -> delegate to standard getBean method.
            return parentBeanFactory.getBean(nameToLookup, requiredType);
        }
    }
    
    1. 获得bean定义,如果存在依赖,先实例化每一个依赖bean,注意:不允许循环依赖
    final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
    checkMergedBeanDefinition(mbd, beanName, args);
    
    // Guarantee initialization of beans that the current bean depends on.
    String[] dependsOn = mbd.getDependsOn();
    //如果存在依赖,先实例化每一个依赖bean
    if (dependsOn != null) {
        // 实例化每一个依赖bean
        for (String dep : dependsOn) {
            // 检查循环依赖
            if (isDependent(beanName, dep)) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
            }
            // 实例化依赖bean
            registerDependentBean(dep, beanName);
            try {
                getBean(dep);
            }
            catch (NoSuchBeanDefinitionException ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
            }
        }
    }
    
    1. 实例化bean

    方法调用流程:

    createBean > doCreateBean > populateBean

    其中doCreateBean:

    1. 从BeanDefinition生成BeanWrapper
    2. 将BeanWrapper和BeanDefinition.getPropertyValues() 传给populateBean,实例化bean

    finishRefresh()

    protected void finishRefresh() {
        // 初始化生命周期处理器
        initLifecycleProcessor();
    
        // 刷新生命周期处理器状态 running = true
        getLifecycleProcessor().onRefresh();
    
        // 发布上下文初始化完成事件ContextRefreshedEvent
        publishEvent(new ContextRefreshedEvent(this));
    
        // 如果处于活动状态,将自己注册到LiveBeans
        LiveBeansView.registerApplicationContext(this);
    }
    

    总结

    Spring IoC Container时序图

  • 相关阅读:
    MySQL 学习(六) InnoDB事务及MVCC
    MySQL学习(二) 存储过程
    一个二级缓存实例 (多级缓存)
    MySQL 学习(五) InnoDB架构
    验证POST接口是否可跨域(自用小工具,自用测试页面)
    用WindowsAppSDK(WASDK)优雅的开发上位机应用
    用PC windows作为Mac macos的扩展屏
    第一次使用webpack
    前端代码压缩工具closesure compiler
    JS代码操作CSS样式文件
  • 原文地址:https://www.cnblogs.com/gcdd/p/12292313.html
Copyright © 2020-2023  润新知