《深入理解Spring原理》 03-IOC容器初始化详解

     Spring可以轻松创建Java企业应用程序,它提供了在企业环境中使用Java语言所需的一切 。要使用Spring 必须要先构建 IOC容器,没有它Spring无法正常工作。本文将详细讲解Spring IOC 初始化机制及学习总结。

     如下图所示:

         定义了一个Person对象,和一个实现BeanPostProcessor接口的自定义类,本文将以此代码为基础来深入学习Spring IOC初始化流程:

//XML Bean 配置



  
  



/**
 * 

* test spring IOC *

* @author [email protected] */ public class DemoApplication { /** * definite a bean with Person */ @Data public static class Person { private String email; public Person() { System.out.println("new Person()"); } public void init() { System.out.println("init() ..........."); } } /** * definite a custome BeanPostprocessor with HelloBeanPostProcessor */ public static class HelloBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("-----------------------postProcessBeforeInitialization..."); return null; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("-----------------------postProcessAfterInitialization..."); return null; } } /** * test ioc init * @param args */ public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); } } //打印台输出结果 new Person() -----------------------postProcessBeforeInitialization... init() ........... -----------------------postProcessAfterInitialization...

   

1. Spring IOC 容器初始化流程

   XML 方式配置元数据:

       以 ApplicationContext 子类ClassPathXmlApplicationContext为切入点解析XML元数据

  注解方式配置元数据:

      以 ApplicationContext 子类 AnnotationConfigApplicationContext 为切入点解析注解元数据

  不管是使用XMl 方式还是使用注解的方式配置元数据,其底层核心实现都是一样的。本章以XML配置文件形式来了解Spring Ioc容器。
 

      首先通过 new ClassPathXmlApplicationContext 这句代码可以找到 IOC 容器初始化入口方法:

//IOC 初始化入口
@Override 
public void refresh() throws BeansException,IllegalStateException {
    synchronized(this.startupShutdownMonitor) {
        // 开启初始化标志,为刷新做准备
        prepareRefresh();

        // 解析XML配置将Bean转换为Beandefinition,并刷新BeanFactory子容器
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // 创建BeanFactory
        prepareBeanFactory(beanFactory);

        try {
            // 注册实现了 BeanPostProcessor接口的bean
            postProcessBeanFactory(beanFactory);

            // 初始化和执行 BeanFactoryPostProcessor beans
            invokeBeanFactoryPostProcessors(beanFactory);

            // 初始化和执行 BeanPostProcessor beans
            registerBeanPostProcessors(beanFactory);

            // Initialize message source for this context.
            initMessageSource();

            // Initialize event multicaster for this context.
            initApplicationEventMulticaster();

            // 刷新由子类实现的方法
            onRefresh();

            // Check for listener beans and register them.
            registerListeners();

            // 初始化 non-lazy-init单例bean,并完成 beanFactory初始化
            finishBeanFactoryInitialization(beanFactory);

            // Last step: publish corresponding event.
            finishRefresh();
        }

        catch(BeansException ex) {
            if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex);
            }

            // Destroy already created singletons to avoid dangling resources.
            destroyBeans();

            // Reset 'active' flag.
            cancelRefresh(ex);

            // Propagate exception to caller.
            throw ex;
        }

        finally {
            // Reset common introspection caches in Spring's core, since we
            // might not ever need metadata for singleton beans anymore...
            resetCommonCaches();
        }
    }
}

 上图展示了Spring IOC 初始化过程中要执行的所有流程,总的来说ApplicationContext必须要完成一下几件事:

《深入理解Spring原理》 03-IOC容器初始化详解_第1张图片

  Step1:构建BeanFactory

   构建BeanFactory过程主要体现在refresh()方法前三行代码:

prepareRefresh();

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

prepareBeanFactory(beanFactory);

   prepareRefresh()主要设置容器开始标识、准备需要的配置信息

   ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory() 这行代码比较关键,因为它做了足够多的事情:

  •     准备BeanFactory
  •     将XML中的Bean配置转换为Spring可以识别的 BeanDefinition

《深入理解Spring原理》 03-IOC容器初始化详解_第2张图片

   prepareBeanFactory() : 配置 BeanFacotey上下文配置信息

   经过上面三个方法的执行后,此时IOC容器可以获取到用户配置的Bean、生成BeanFactory雏形。

   

Step2: 注册感兴趣的事件

 “ 注册感兴趣的事件” 这个过程中,比较重要的是以下几个方法:

postProcessBeanFactory(beanFactory);

invokeBeanFactoryPostProcessors(beanFactory);

registerBeanPostProcessors(beanFactory);

   为什么这几个方法比较重要呢?

   因为这几个方法完成了  Bean 生命周期 (init、destroy) 、BeanPostProccessor、Aware接口注入 这一系列过程

spring为开发人员提供了足够的扩展点
比如:
  Bean 生命周期 (init、destroy)
  BeanPostProccessor
  Aware接口注入

   经过对上面三个方法Debug,找到了核心调用方法 :

   AbstractAutowireCapableBeanFactory中的 initializeBean 方法:该方法会对目标Bean进行包装

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged((PrivilegedAction < Object > )() - >{
            invokeAwareMethods(beanName, bean);
            return null;
        },
        getAccessControlContext());
    } else {
        //执行实现Aware接口注入逻辑
        invokeAwareMethods(beanName, bean);
    }

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        //执行 自定义 BeanPostProcessor 的  postProcessBeforeInitialization 方法
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        //执行 Bean 的init方法
        invokeInitMethods(beanName, wrappedBean, mbd);
    } catch(Throwable ex) {
        throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex);
    }
    if (mbd == null || !mbd.isSynthetic()) {
        //执行 自定义 BeanPostProcessor 的  postProcessAfterInitialization方法
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}

 

//这也解释了打印台为什么会打印出下面的语句
new Person()
-----------------------postProcessBeforeInitialization...
init() ...........
-----------------------postProcessAfterInitialization...

 

Step3: 创建Bean实例对象

     “创建 Bean实例对象”  这个过程主要集中在   finishBeanFactoryInitialization(beanFactory) 方法中。

      finishBeanFactoryInitialization 中的 beanFactory.preInstantiateSingletons(); 会真正的进行 Bean 实例化:

@Override public void preInstantiateSingletons() throws BeansException {
    if (logger.isDebugEnabled()) {
        logger.debug("Pre-instantiating singletons in " + this);
    }

    // Iterate over a copy to allow for init methods which in turn register new bean definitions.
    // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
    List < String > beanNames = new ArrayList < >(this.beanDefinitionNames);

    // Trigger initialization of all non-lazy singleton beans...
    for (String beanName: beanNames) {
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            if (isFactoryBean(beanName)) {
                Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                if (bean instanceof FactoryBean) {
                    final FactoryBean < ?>factory = (FactoryBean < ?>) bean;
                    boolean isEagerInit;
                    if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                        isEagerInit = AccessController.doPrivileged((PrivilegedAction < Boolean > )((SmartFactoryBean < ?>) factory) : :isEagerInit, getAccessControlContext());
                    } else {
                        isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean < ?>) factory).isEagerInit());
                    }
                    if (isEagerInit) {
                        getBean(beanName);
                    }
                }
            } else {
                getBean(beanName);
            }
        }
    }

    // Trigger post-initialization callback for all applicable beans...
    for (String beanName: beanNames) {
        Object singletonInstance = getSingleton(beanName);
        if (singletonInstance instanceof SmartInitializingSingleton) {
            final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
            if (System.getSecurityManager() != null) {
                AccessController.doPrivileged((PrivilegedAction < Object > )() - >{
                    smartSingleton.afterSingletonsInstantiated();
                    return null;
                },
                getAccessControlContext());
            } else {
                smartSingleton.afterSingletonsInstantiated();
            }
        }
    }
}

     这一步方法结束之后,基本上就完成了 IOC 的初始化。

   

上述内容如有不妥之处,还请读者指出,共同探讨,共同进步!

@author : [email protected]

你可能感兴趣的:(Spring,设计思想)