• SpringBoot实践笔记——IOC容器


    本文主要讲解SpringBoot从主方法入口到容器刷新那边的过程,至于容器刷新过程,可以参考之前写的文章:重新学习Spring注解——Spring容器

    一般主方法如下:

    @SpringBootApplication
    public class DemoApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    }

    跟进主方法,我们来到了类:org.springframework.context.ConfigurableApplicationContext

        /**
         * Static helper that can be used to run a {@link SpringApplication} from the
         * specified source using default settings.
         * @param primarySource the primary source to load
         * @param args the application arguments (usually passed from a Java main method)
         * @return the running {@link ApplicationContext}
         */
        public static ConfigurableApplicationContext run(Class<?> primarySource,
                String... args) {
            return run(new Class<?>[] { primarySource }, args);
        }
        // 继续往下走
        
        /**
         * Static helper that can be used to run a {@link SpringApplication} from the
         * specified sources using default settings and user supplied arguments.
         * @param primarySources the primary sources to load
         * @param args the application arguments (usually passed from a Java main method)
         * @return the running {@link ApplicationContext}
         */
        public static ConfigurableApplicationContext run(Class<?>[] primarySources,
                String[] args) {
            return new SpringApplication(primarySources).run(args);
        }
    
        // 点击run,再往下走    
        /**
         * Run the Spring application, creating and refreshing a new
         * {@link ApplicationContext}.
         * @param args the application arguments (usually passed from a Java main method)
         * @return a running {@link ApplicationContext}
         */
        public ConfigurableApplicationContext run(String... args) {
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            ConfigurableApplicationContext context = null;
            Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
            configureHeadlessProperty();
            SpringApplicationRunListeners listeners = getRunListeners(args);
            listeners.starting();
            try {
                ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                        args);
                ConfigurableEnvironment environment = prepareEnvironment(listeners,
                        applicationArguments);
                configureIgnoreBeanInfo(environment);
                Banner printedBanner = printBanner(environment);
                // 采用策略模式决定创建什么容器:创建ServletWebServer或ReactiveWebServer或主容器
                context = createApplicationContext();
                exceptionReporters = getSpringFactoriesInstances(
                        SpringBootExceptionReporter.class,
                        new Class[] { ConfigurableApplicationContext.class }, context);
                prepareContext(context, environment, listeners, applicationArguments,
                        printedBanner);
                // 容器刷新
                refreshContext(context);
                afterRefresh(context, applicationArguments);
                stopWatch.stop();
                if (this.logStartupInfo) {
                    new StartupInfoLogger(this.mainApplicationClass)
                            .logStarted(getApplicationLog(), stopWatch);
                }
                listeners.started(context);
                callRunners(context, applicationArguments);
            }
            catch (Throwable ex) {
                handleRunFailure(context, ex, exceptionReporters, listeners);
                throw new IllegalStateException(ex);
            }
    
            try {
                listeners.running(context);
            }
            catch (Throwable ex) {
                handleRunFailure(context, ex, exceptionReporters, null);
                throw new IllegalStateException(ex);
            }
            return context;
        }    
        
        // 接上面:context = createApplicationContext();
        /**
         * Strategy method used to create the {@link ApplicationContext}. By default this
         * method will respect any explicitly set application context or application context
         * class before falling back to a suitable default.
         * @return the application context (not yet refreshed)
         * @see #setApplicationContextClass(Class)
         */
        protected ConfigurableApplicationContext createApplicationContext() {
            Class<?> contextClass = this.applicationContextClass;
            if (contextClass == null) {
                try {
                    switch (this.webApplicationType) {
                    case SERVLET:
                        contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
                        break;
                    case REACTIVE:
                        contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
                        break;
                    default:
                        contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
                    }
                }
                catch (ClassNotFoundException ex) {
                    throw new IllegalStateException(
                            "Unable create a default ApplicationContext, "
                                    + "please specify an ApplicationContextClass",
                            ex);
                }
            }
            return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
        }
        
        // 容器刷新
        private void refreshContext(ConfigurableApplicationContext context) {
            // 关键方法:
            refresh(context);
            if (this.registerShutdownHook) {
                try {
                    context.registerShutdownHook();
                }
                catch (AccessControlException ex) {
                    // Not allowed in some environments.
                }
            }
        }
        
        //     接上面关键方法:refresh(context);
        /**
         * Refresh the underlying {@link ApplicationContext}.
         * @param applicationContext the application context to refresh
         */
        protected void refresh(ApplicationContext applicationContext) {
            Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
            // 容器刷新
            ((AbstractApplicationContext) applicationContext).refresh();
        }
    View Code
    refresh()真正的方法如下:org.springframework.context.support.AbstractApplicationContext
    @Override
        public void refresh() throws BeansException, IllegalStateException {
            synchronized (this.startupShutdownMonitor) {
                // 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);
    
                try {
                    // 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();
                }
    
                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();
                }
            }
        }
    View Code

    上面提到的策略模式,会生成三面三种容器中的一种:

        /**
         * The class name of application context that will be used by default for non-web
         * environments.
         */
        public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
                + "annotation.AnnotationConfigApplicationContext";
    
        /**
         * The class name of application context that will be used by default for web
         * environments.
         */
        public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
                + "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
    
        /**
         * The class name of application context that will be used by default for reactive web
         * environments.
         */
        public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
                + "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";

    结合下图,核实是否子类(截图虹口),刷新方法一样?

    ① 针对:org.springframework.context.annotation.AnnotationConfigApplicationContext

    public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {}
    
    public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {}
    
    // 说明:AnnotationConfigApplicationContext与GenericApplicationContext都没有重写refresh()

    ② 针对:org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext

    public class AnnotationConfigReactiveWebServerApplicationContext
            extends ReactiveWebServerApplicationContext implements AnnotationConfigRegistry {}
            
    public class ReactiveWebServerApplicationContext
            extends GenericReactiveWebApplicationContext
            implements ConfigurableWebServerApplicationContext {        
            
        // 点击super.refresh();跳转org.springframework.context.support.AbstractApplicationContext#refresh        
        @Override
        public final void refresh() throws BeansException, IllegalStateException {
            try {
                super.refresh();
            }
            catch (RuntimeException ex) {
                stopAndReleaseReactiveWebServer();
                throw ex;
            }
        }
    }

    ③针对:org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext

    public class AnnotationConfigServletWebServerApplicationContext
            extends ServletWebServerApplicationContext implements AnnotationConfigRegistry {}
            
    public class ServletWebServerApplicationContext extends GenericWebApplicationContext
            implements ConfigurableWebServerApplicationContext {        
        
        // 点击super.refresh();跳转org.springframework.context.support.AbstractApplicationContext#refresh    
        @Override
        public final void refresh() throws BeansException, IllegalStateException {
            try {
                super.refresh();
            }
            catch (RuntimeException ex) {
                stopAndReleaseWebServer();
                throw ex;
            }
        }
    }

    所以:容器刷新都是调用 org.springframework.context.support.AbstractApplicationContext#refresh方法。

  • 相关阅读:
    [MySql]explain用法及实践
    [Angularjs]asp.net mvc+angularjs+web api单页应用
    asp.net预定义的HttpModule
    不使用配置文件动态注册HttpModule
    DELPHI NEXTGEN编译开关
    mormot中间件成功匹配客户端FDMemTable和ClientDataSet
    firedac数据集和字符串之间相互转换
    Delphi XE中String、ANSIString、TBytes之间的转换
    论DELPHI三层的数据序列格式的变化
    MORMOT的数据序列
  • 原文地址:https://www.cnblogs.com/gzhcsu/p/13562340.html
Copyright © 2020-2023  润新知