Spring IoC 容器生命周期

• 启动

• 运行

• 停止

代码示例

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.geekbang.thinking.in.spring.ioc.overview.container;

import org.geekbang.thinking.in.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Map;

/**
 * 29 | Spring IoC容器生命周期:IoC容器启停过程中发生了什么?
 * 只是一个大概介绍
 * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
 * @since
 */
@Configuration
public class AnnotationApplicationContextAsIoCContainerDemo {

    public static void main(String[] args) {
        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 将当前类 AnnotationApplicationContextAsIoCContainerDemo 作为配置类(Configuration Class)
        applicationContext.register(AnnotationApplicationContextAsIoCContainerDemo.class);
        // 启动应用上下文
        applicationContext.refresh();
        /*
            applicationContext的refresh()方法就是以前针对spring启动过程分析的核心方法, 这里只是简单一讲,
            点进去看看实现:
            @Override
            public void refresh() throws BeansException, IllegalStateException {
                synchronized (this.startupShutdownMonitor) {
                // synchronized 这里加锁是因为applicationContext可以在程序的任何位置创建,
                而spring 的设计者并不知道你会不会多线程创建什么的, 当然要加锁
                    // Prepare this context for refreshing. 看下面讲解
                    prepareRefresh();

                    // Tell the subclass to refresh the internal bean factory.
                    // 这里去刷新一个内部的beanFactory, 而且是用子类来实现
                    // 有两种可能, 一种是空实现, 一种是抽象实现, 看下面讲解
                    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

                    // Prepare the bean factory for use in this context.
                    // 这里面会有一大堆操作,
                    // 里面有两个方法涉及到前面我们讲的内建的 bean的注入和非bean(依赖)注入
                    // beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
                    // beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
                    // 后面这里也会有详细讲解
                    prepareBeanFactory(beanFactory);

                    try {
                        // Allows post-processing of the bean factory in context subclasses.
                        // 这个方法就是一个BeanFactory的扩展点, 可以自己对BeanFactory(容器)进行API的扩展
                        postProcessBeanFactory(beanFactory);

                        // Invoke factory processors registered as beans in the context.
                        // 上面调整完了这里执行
                        invokeBeanFactoryPostProcessors(beanFactory);

                        // Register bean processors that intercept bean creation.
                        // 这个方法则是对Bean进行调整, 就是对注入的用户定义的bean的调整
                        // 这里只是注册, 具体的调用是在BeanFactory中进行的
                        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();
                    }

                    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();
                    }
                }
            }

            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.
                // 后面在 Environment抽象里面会讲到这一部分
                initPropertySources();

                // Validate that all properties marked as required are resolvable:
                // see ConfigurablePropertyResolver#setRequiredProperties
                // 与校验相关的一个部分
                getEnvironment().validateRequiredProperties();

                // Store pre-refresh ApplicationListeners...
                // earlyApplicationListeners会在spring的事件中进行分析, 这个场景比较复杂
                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<>();
            }

            protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
                // 看得出来这里提供的是一个不完整的实现, 下面两个方法都是抽象实现.
                // refreshBeanFactory有一个常见的实现就是
                // org.springframework.context.support.AbstractRefreshableApplicationContext.
                refreshBeanFactory, 看后面
                refreshBeanFactory();
                return getBeanFactory();
                // 特别注意一定, 玩游戏看颜色, 学技术看版本
                // 我们分析用的是5.2.2.RELEASE版本, 如果低于或高于这个版本, 这里看到的代码都不一样
                // 如果用的是SNAPSHOT版本, 源码可能会随之覆盖和更新, 因此一定要用RELEASE版本或MILESTONE版本
            }

            @Override
            protected final void refreshBeanFactory() throws BeansException {
                // 如果存在BeanFactory就先销毁
                if (hasBeanFactory()) {
                    destroyBeans();
                    closeBeanFactory();
                }
                try {
                    // 之前看过的, 创建一个DefaultListableBeanFactory,
                    // 这是个组合, 同时与ApplicationContext不是一个对象
                    DefaultListableBeanFactory beanFactory = createBeanFactory();
                    beanFactory.setSerializationId(getId());
                    customizeBeanFactory(beanFactory);
                    // 读取bean的定义
                    loadBeanDefinitions(beanFactory);
                    // 这里有把锁, 同样也是因为refreshBeanFactory可以外部调用, 不是主线程调用的,
                    // 加了锁防止线程不安全
                    synchronized (this.beanFactoryMonitor) {
                        this.beanFactory = beanFactory;
                    }
                }
                catch (IOException ex) {
                    throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
                }
            }

            至于资源的操作其实是靠继承的父类来完成的: DefaultResourceLoader
            public abstract class AbstractApplicationContext extends DefaultResourceLoader
		    implements ConfigurableApplicationContext

		    // 在web容器中的调用会复杂一些, 如tomcat等, 在springBoot中会有一些嵌套,
		    // 但最终还是要走上面那一套流程
        */

        // 依赖查找集合对象
        lookupCollectionByType(applicationContext);

        applicationContext.close();
        /*
            关闭应用上下文
            public void close() {
                // 关闭要相对比较简单
                synchronized (this.startupShutdownMonitor) {
                    doClose();
                    // If we registered a JVM shutdown hook, we don't need it anymore now:
                    // We've already explicitly closed the context.
                    if (this.shutdownHook != null) {
                        try {
                            Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
                        }
                        catch (IllegalStateException ex) {
                            // ignore - VM is already shutting down
                        }
                    }
                }
            }

            protected void doClose() {
                // Check whether an actual close attempt is necessary...
                if (this.active.get() && this.closed.compareAndSet(false, true)) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Closing " + this);
                    }

                    LiveBeansView.unregisterApplicationContext(this);

                    try {
                        // Publish shutdown event.
                        publishEvent(new ContextClosedEvent(this));
                    }
                    catch (Throwable ex) {
                        logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
                    }

                    // Stop all Lifecycle beans, to avoid delays during individual destruction.
                    if (this.lifecycleProcessor != null) {
                        try {
                            this.lifecycleProcessor.onClose();
                        }
                        catch (Throwable ex) {
                            logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
                        }
                    }

                    // Destroy all cached singletons in the context's BeanFactory.
                    // 可以销毁所有的bean
                    destroyBeans();

                    // Close the state of this context itself.
                    // 关闭掉BeanFactory
                    closeBeanFactory();

                    // Let subclasses do some final clean-up if they wish...
                    // 这个方法可以自定义, 实现自己需要的关闭方法
                    onClose();

                    // Reset local application listeners to pre-refresh state.
                    if (this.earlyApplicationListeners != null) {
                        this.applicationListeners.clear();
                        this.applicationListeners.addAll(this.earlyApplicationListeners);
                    }

                    // Switch to inactive.
                    this.active.set(false);
                }
            }
         */

    }

    /**
     * 通过 Java 注解的方式,定义了一个 Bean
     * 相当于用 Java 代码 进行配置
     */
    @Bean
    public User user() {
        User user = new User();
        user.setId(1L);
        user.setName("小马哥");
        return user;
    }

    private static void lookupCollectionByType(BeanFactory beanFactory) {
        if (beanFactory instanceof ListableBeanFactory) {
            ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
            Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
            System.out.println("查找到的所有的 User 集合对象:" + users);
        }
    }

}

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐