美文网首页
Spring IOC的创建原理

Spring IOC的创建原理

作者: Coding小聪 | 来源:发表于2018-06-11 23:10 被阅读14次

    前言

    我们将通过Spring(具体版本为:4.3.9.RELEASE)注解的方式来分析IOC容器的创建过程,主要通过AnnotationConfigApplicationContext类。入口程序如下

    @Test
    public void test(){
        AnnotationConfigApplicationContext applicationContext = new
              AnnotationConfigApplicationContext(MainConfig.class);
        System.out.println("IOC容器创建完毕");
        Object person = applicationContext.getBean("person");
        Person person1 = applicationContext.getBean(Person.class);
        System.out.println(person == person1);
    }
    

    其中MainConfig是Spring的注解配置类,其代码如下

    @Configuration
    public class MainConfig {
    
        /**
         * @Bean注解的value属性用来定义注册到IOC容器中的bean name
         * 如果不指定value属性,则用方法名作为bean name
         * @return
         */
        @Bean(value = "person")
        public Person getPerson(){
            Person person = new Person();
            person.setName("Jerry");
            person.setAge(18);
            person.setNickName("J");
            return person;
        }
    }
    

    AnnotationConfigApplicationContext的继承体系

    AnnotationConfigApplicationContext继承体系图
    由上图可知,AnnotationConfigApplicationContextApplicationContext接口某个具体实现类,而ApplicationContextBeanFactory的子接口。所以我们可以将AnnotationConfigApplicationContext看成是一种BeanFactory,他们的本质都是一样的。

    ApplicationContext和BeanFactory都是用于加载Bean的,这两个类都可以看成是Spring IOC容器,但是ApplicationContext比BeanFactory提供了更多的扩展功能。

    常见的ApplicationContext


    上图中用红框框起来的是一些常见的ApplicationContext,它们用于各种不同的场景。在这些类实例化的过程中,都会直接或间接的调用AbstractApplicationContext.refresh()方法。而AbstractApplicationContext.refresh()方法的执行过程就是IOC容器的创建过程。下面来分析一下refresh()方法的执行过程。

    refresh()执行流程

    refresh()方法很重要,它是各种IOC容器初始化的入口。首先需要知道的是refresh()方法运用了“模板方法”的设计模式,后面会出个专栏分析Spring中运用的设计模式。先来看看refresh()的源码

    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // 1. 准备上下文信息
            prepareRefresh();
            // Tell the subclass to refresh the internal bean factory.
            // 2. 初始化BeanFactory
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
            // 3. 对BeanFactory进行功能填充
            prepareBeanFactory(beanFactory);
    
            try {
                // 4. 子类覆盖的方法,用于做特殊的处理,这是个钩子方法
                postProcessBeanFactory(beanFactory);
                // 5. 激活各种BeanFactoryPostProcessor处理器
                invokeBeanFactoryPostProcessors(beanFactory);
                // 6. 注册各种Bean的后置处理器,后置处理器的调用发生在getBean
                registerBeanPostProcessors(beanFactory);
                // 7. 国际化处理
                initMessageSource();
                // 8. 在容器中初始化消息广播器
                initApplicationEventMulticaster();
                // 9. 子类覆盖的方法,各⼦类来初始化其他的bean,钩子方法
                onRefresh();
                // 10. 注册Listener到消息广播器中
                registerListeners();
                // 11. 初始化剩余的所有非懒加载的单实例bean
                finishBeanFactoryInitialization(beanFactory);
                // 12. 发送ContextRefreshEvent广播,完成刷新过程
                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...
                // 13. 清除缓存
                resetCommonCaches();
            }
        }
    }
    

    refresh()正常执行完毕,即表明创建好IOC容器。分析源码可以知道refresh()方法做了13件事。

    1. 准备上下文信息;
    2. 创建BeanFactory;
    3. 对BeanFactory进行功能填充;
    4. 子类覆盖的方法,用于做特殊的处理,这是个钩子方法;
    5. 激活各种BeanFactoryPostProcessor处理器;
    6. 注册各种Bean的后置处理器,后置处理器的调用发生在getBean;
    7. 国际化处理;
    8. 在容器中初始化消息广播器;
    9. 子类覆盖的方法,各⼦类来初始化其他的bean,钩子方法;
    10. 注册Listener到消息广播器中;
    11. 初始化剩余的所有非懒加载的单实例bean;
    12. 发送ContextRefreshEvent广播,完成刷新过程;
    13. 清除缓存。

    1. 准备上下文信息

    protected void prepareRefresh() {
        this.startupDate = System.currentTimeMillis();
        this.closed.set(false);
        this.active.set(true);
    
        if (logger.isInfoEnabled()) {
            logger.info("Refreshing " + this);
        }
    
        // 初始化property资源,扩展点,留给子类实现
        initPropertySources();
    
        // 验证需要的配置文件是否加载到环境中
        // 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>();
    }
    

    2. 创建BeanFactory

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

    这个方法执行完毕之后,ApplicationContext就拥有了BeanFactory的功能。这段代码做了两件事:2.1 初始化BeanFactory;2.2 获取BeanFactory。

    2.1 初始化BeanFactory

    refreshBeanFactory();用来初始化BeanFactory,它最终调用的是GenericApplicationContext.refreshBeanFactory()方法,代码如下:

    protected final void refreshBeanFactory() throws IllegalStateException {
        if (!this.refreshed.compareAndSet(false, true)) {
            throw new IllegalStateException(
                    "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
        }
        this.beanFactory.setSerializationId(getId());
    }
    

    主要是通过getId()方法给BeanFactory设置serializationId的属性值,此处设置的值为:"org.springframework.context.annotation.AnnotationConfigApplicationContext@6cc7b4de"

    2.2 获取BeanFactory
    public final ConfigurableListableBeanFactory getBeanFactory() {
        return this.beanFactory;
    }
    

    此处返回的是DefaultListableBeanFactory

    3. 对BeanFactory进行功能填充

    protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // Tell the internal bean factory to use the context's class loader etc.
        beanFactory.setBeanClassLoader(getClassLoader());
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
        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);
        beanFactory.ignoreDependencyInterface(ApplicationContextAware.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);
    
        // Register early post-processor for detecting inner beans as ApplicationListeners.
        beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
    
        // 增加对AspectJ的支持
        if (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
        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());
        }
    }
    

    此方法是对BeanFactory进行一些设置。关于这一块的解说可以参考容器的功能扩展(二)功能扩展

    4. postProcessBeanFactory

    postProcessBeanFactory方法是一个扩展点,在AbstractApplicationContext中是一个空方法,它主要是让子类可以重写以实现它们自己的特殊逻辑。而AnnotationConfigApplicationContext并没有对该类进行重写。

    5.激活各种BeanFactoryPostProcessor处理器

    BeanFactoryPostProcessorBeanPostProcessor都是Spring提供的扩展点,可以通过它们对bean的定义修改。

     protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
         PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
    
         // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
         // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
         if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
             beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
             beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
         }
     }
    

    激活BeanFactoryPostProcessor的工作会委托给PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()进行处理。

    6. 注册各种Bean的后置处理器

    Bean的后置处理器的方法也是委托给PostProcessorRegistrationDelegate处理,具体方法为:registerBeanPostProcessors()。这⾥只是注册,真正的调⽤是在getBean的时候

    待续

    相关文章

      网友评论

          本文标题:Spring IOC的创建原理

          本文链接:https://www.haomeiwen.com/subject/dmukeftx.html