• Spring Boot源码阅读启动主流程(一)


    说明

    待定

    main方法

    通过以下方法就完成了自定义启动和容器初始化是怎么完成的呢

    @SpringBootApplication
    public class FinancialAnalysisApplication {
    
        public static void main(String[] args) {
    //<1>run启动 SpringApplication.run(FinancialAnalysisApplication.
    class, args); } }

    <1>

    org.springframework.boot.SpringApplication#run

     public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
            //包装成数组类型 我们表示我们可以配置多个
            return run(new Class<?>[] { primarySource }, args);
        }
     public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
            //<2>我们先看构造函数初始化做了什么 <8>run启动
            return new SpringApplication(primarySources).run(args);
        }

    <2>

     @SuppressWarnings({ "unchecked", "rawtypes" })
        public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
            this.resourceLoader = resourceLoader;
            Assert.notNull(primarySources, "PrimarySources must not be null");
            //我们的启动类指定的class 如:    SpringApplication.run(FinancialAnalysisApplication.class, args);
            this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
            //<3>获得环境类型
            this.webApplicationType = WebApplicationType.deduceFromClasspath();
            //----------------------------<4>getSpringFactoriesInstances方法是在spring.factories找到实现了指定类型的类---------------------------
            /**
             * 获取BootstrapRegistryInitializer的实现类 默认没有实现
             */
            this.bootstrapRegistryInitializers = new ArrayList<>(
                    getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
            /**
             * ApplicationContextInitializer 看spring-boot.jar包下的的默认配置有
             * org.springframework.context.ApplicationContextInitializer=\
             * org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
             * org.springframework.boot.context.ContextIdApplicationContextInitializer,\
             * org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
             * org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
             * org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
             */
            setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
            /**
             *  ApplicationListener 看spring-boot.jar包下的的默认配置  后续由SpringApplicationRunListeners在各个时机委托给EVentPublishingRunListener 发送对应的Event事件 由以下监听器监听
             * # Application Listeners
             * org.springframework.context.ApplicationListener=\
             * org.springframework.boot.ClearCachesApplicationListener,\
             * org.springframework.boot.builder.ParentContextCloserApplicationListener,\
             * org.springframework.boot.context.FileEncodingApplicationListener,\
             * org.springframework.boot.context.config.AnsiOutputApplicationListener,\
             * org.springframework.boot.context.config.DelegatingApplicationListener,\
             * org.springframework.boot.context.logging.LoggingApplicationListener,\
             * org.springframework.boot.env.EnvironmentPostProcessorApplicationListener
             */
            setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
            //<7>这里主要是获取main方法进入的类型
            this.mainApplicationClass = deduceMainApplicationClass();
        }

    <3>

    org.springframework.boot.WebApplicationType#deduceFromClasspath

      private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";
        private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";
        private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";
        private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
                "org.springframework.web.context.ConfigurableWebApplicationContext" };
        static WebApplicationType deduceFromClasspath() {
            //如果可以加载DispatcherHandler 同时WEBMVC_INDICATOR_CLASS JERSEY_INDICATOR_CLASS不存在则类型是REACTIVE
            if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
                    && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
                //REACTIVE则是一种比较新的非阻塞的web框架,对应spring-webflux,需要启动支持reactive的web容器
                return WebApplicationType.REACTIVE;
            }
            //如果SERVLET_INDICATOR_CLASSES 都无法加载则是NoNE
            for (String className : SERVLET_INDICATOR_CLASSES) {
                if (!ClassUtils.isPresent(className, null)) {
                    //NONE就是什么都没有,按照正常的代码走即可不需要额外启动web容器如tomcat等
                    return WebApplicationType.NONE;
                }
            }
            //SERVLET则代表这是一个传统的servlet的web程序,对应SpringMVC 默认是SERVLET
            return WebApplicationType.SERVLET;
        }

    <4>

    org.springframework.boot.SpringApplication#getSpringFactoriesInstances

    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
            return getSpringFactoriesInstances(type, new Class<?>[] {});
        }
     private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
            //获得当前类的类加载器
            ClassLoader classLoader = getClassLoader();
            // <5>从spring.factories获取对应类型配置类的全名称
            Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
            //反射创建
            List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
            //如果打了@order注解 则根据@Order注解优先级排序返回
            AnnotationAwareOrderComparator.sort(instances);
            return instances;
        }

    <5>

    org.springframework.core.io.support.SpringFactoriesLoader#loadFactoryNames

        public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
            //获取查找类型的名字后续通过他为key查找对应的类型
            String factoryTypeName = factoryType.getName();
            //<6>触发加载根据类型封装成map  然后通过factoryType去map获取对应的实现类配置的名字
            return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
        }

    <6>

    org.springframework.core.io.support.SpringFactoriesLoader#loadSpringFactories

      public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
        private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
            //先确定当前ClassLoader是否加载了配置 防止重复加载如果加载了直接返回加载后的map
            Map<String, List<String>> result = cache.get(classLoader);
            if (result != null) {
                return result;
            }
    
            result = new HashMap<>();
            try {
                //获得所有META-INF/spring.factories下的配置
                Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
                //遍历加载各个url下的文件
                while (urls.hasMoreElements()) {
                    URL url = urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    //因为是properties格式配置所以转换为properties
                    /**
                     * 如:
                     * org.springframework.boot.SpringApplicationRunListener=\
                     * org.springframework.boot.context.event.EventPublishingRunListener
                     */
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    //遍历封装到map
                    for (Map.Entry<?, ?> entry : properties.entrySet()) {
                        String factoryTypeName = ((String) entry.getKey()).trim();
                        String[] factoryImplementationNames =
                                StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
                        for (String factoryImplementationName : factoryImplementationNames) {
                            result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
                                    .add(factoryImplementationName.trim());
                        }
                    }
                }
    
                // 去重
                result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
                        .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
                //封装到cache 后续获取直接从cache获取
                cache.put(classLoader, result);
            }
            catch (IOException ex) {
                throw new IllegalArgumentException("Unable to load factories from location [" +
                        FACTORIES_RESOURCE_LOCATION + "]", ex);
            }
            return result;
        }

    <7>

    org.springframework.boot.SpringApplication#deduceMainApplicationClass

      private Class<?> deduceMainApplicationClass() {
            try {
                //获得当前执行堆栈
                StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
                //遍历知道获取main方法的入口堆栈 并获取类的class
                for (StackTraceElement stackTraceElement : stackTrace) {
                    if ("main".equals(stackTraceElement.getMethodName())) {
                        return Class.forName(stackTraceElement.getClassName());
                    }
                }
            }
            catch (ClassNotFoundException ex) {
                // Swallow and continue
            }
            return null;
        }

     <8>

    org.springframework.boot.SpringApplication#run

    public ConfigurableApplicationContext run(String... args) {
            //启动开始时间
            long startTime = System.nanoTime();
            //<9>创建DefaultBootstrapContext
            DefaultBootstrapContext bootstrapContext = createBootstrapContext();
            ConfigurableApplicationContext context = null;
            //设置java.awt.headless配置
            configureHeadlessProperty();
            //<10>获得监听器
            SpringApplicationRunListeners listeners = getRunListeners(args);
    //调用starting 发送ApplicationStartingEvent事件 starting事件 listeners.starting(bootstrapContext,
    this.mainApplicationClass); try { //封装系统变量 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); //<11>加载环境变量 ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments); //spring.beaninfo.ignore默认配置为true configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); //<13>通过ApplicationContextFactory创建Spring容器 context = createApplicationContext(); //容器状态设置 context.setApplicationStartup(this.applicationStartup); //<14>容器初始化前的相关配置 prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); //<16>调用容器的refresh方法 进入spring生命周期 refreshContext(context); //钩子方法 子类可以自定义实现 afterRefresh(context, applicationArguments); Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup); } //发送listeners的ApplicationStartedEvent事件 listeners.started(context, timeTakenToStartup); //<15>从容器中获得ApplicationRunner 和CommandLineRunner 完成回调 callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, listeners); throw new IllegalStateException(ex); } try { Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime); listeners.ready(context, timeTakenToReady); } catch (Throwable ex) { handleRunFailure(context, ex, null); throw new IllegalStateException(ex); } return context; }

    <9>

    org.springframework.boot.SpringApplication#createApplicationContext

      private DefaultBootstrapContext createBootstrapContext() {
            DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
            //调用bootstrapRegistryInitializers我们可以做初始化配置
            this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
            return bootstrapContext;
        }

    <10>

    org.springframework.boot.SpringApplication#getRunListeners

    rivate SpringApplicationRunListeners getRunListeners(String[] args) {
            Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
            //根据getSpringFactoriesInstances 获取实现SpringApplicationRunListener接口 默认是EventpublishingRunListener 通过SpringApplicationRunListeners包装
            /**
             * # Run Listeners
             * org.springframework.boot.SpringApplicationRunListener=\
             * org.springframework.boot.context.event.EventPublishingRunListener 默认 可以持有当前application的引用 所以可以拿到listeners
    * 发送时间则是由spring.factories applicationContextListener监听
    */ return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args), this.applicationStartup); }

    <11>

    org.springframework.boot.SpringApplication#prepareEnvironment

    private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
                                                           DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
            // <12>根据环境初始化environment
            ConfigurableEnvironment environment = getOrCreateEnvironment();
            //将系统变量设置到environment
            configureEnvironment(environment, applicationArguments.getSourceArgs());
    //<17>这里主要是将configurationProperties替换放到第一位 优先级最高 ConfigurationPropertySources.attach(environment);
    //发送listener ApplicationEnviromentPreparedEvent 对应消费将触发我们application.yml配置文件加载 /** * # Run Listeners * org.springframework.boot.SpringApplicationRunListener=\ * org.springframework.boot.context.event.EventPublishingRunListener 默认 */ listeners.environmentPrepared(bootstrapContext, environment); DefaultPropertiesPropertySource.moveToEnd(environment); Assert.state(!environment.containsProperty("spring.main.environment-prefix"), "Environment prefix cannot be set via properties."); bindToSpringApplication(environment); if (!this.isCustomEnvironment) { environment = convertEnvironment(environment); } ConfigurationPropertySources.attach(environment); return environment; }

    <12>

    org.springframework.boot.SpringApplication#getOrCreateEnvironment

    private ConfigurableEnvironment getOrCreateEnvironment() {
            if (this.environment != null) {
                return this.environment;
            }
            switch (this.webApplicationType) {
                case SERVLET:
                    return new ApplicationServletEnvironment();
                case REACTIVE:
                    return new ApplicationReactiveWebEnvironment();
                default:
                    return new ApplicationEnvironment();
            }
        }

    <13>

    com.biaoguoworks.sac.chains.commons.controller.ChainBaseController#createApplicationContext

        private ApplicationContextFactory applicationContextFactory = ApplicationContextFactory.DEFAULT;
        protected ConfigurableApplicationContext createApplicationContext() {
            return this.applicationContextFactory.create(this.webApplicationType);
        }
    
        ApplicationContextFactory DEFAULT = (webApplicationType) -> {
            try {
                switch (webApplicationType) {
                    case SERVLET:
                        return new AnnotationConfigServletWebServerApplicationContext();
                    case REACTIVE:
                        return new AnnotationConfigReactiveWebServerApplicationContext();
                    default:
                        return new AnnotationConfigApplicationContext();
                }
            }
            catch (Exception ex) {
                throw new IllegalStateException("Unable create a default ApplicationContext instance, "
                        + "you may need a custom ApplicationContextFactory", ex);
            }
        };

    <14>

    org.springframework.boot.SpringApplication#prepareContext

    private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
                                    ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
                                    ApplicationArguments applicationArguments, Banner printedBanner) {
            //设置环境变量
            context.setEnvironment(environment);
    //针对BeanNameGenerator resourceLoader、ConversionService设置缺省值 postProcessApplicationContext(context);
    //触发ApplicationContextInitializer回调 也是从spring.factories获取 applyInitializers(context); //发送ApplicationContextInitializedEvent事件 listeners.contextPrepared(context); bootstrapContext.close(context); if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // Add boot specific singleton beans ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); beanFactory.registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { beanFactory.registerSingleton("springBootBanner", printedBanner); } if (beanFactory instanceof AbstractAutowireCapableBeanFactory) { ((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences); if (beanFactory instanceof DefaultListableBeanFactory) { ((DefaultListableBeanFactory) beanFactory) .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } } if (this.lazyInitialization) { context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()); } // Load the sources Set<Object> sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty");
    //source就是我们的启动类,这里主要是将我们的启动类的BeanDefintion加载到BeanFacotry,所以我们再启动类上打相关注解有效 load(context, sources.toArray(
    new Object[0])); //发送ApplicationPreparedEvent事件 listeners.contextLoaded(context); }

    <15>

    org.springframework.boot.SpringApplication#callRunners

     private void callRunners(ApplicationContext context, ApplicationArguments args) {
            List<Object> runners = new ArrayList<>();
            //从容器中获得ApplicationRunner实现
            runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
            runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
            //进行排序
            AnnotationAwareOrderComparator.sort(runners);
            //完成回调
            for (Object runner : new LinkedHashSet<>(runners)) {
                if (runner instanceof ApplicationRunner) {
                    callRunner((ApplicationRunner) runner, args);
                }
                if (runner instanceof CommandLineRunner) {
                    callRunner((CommandLineRunner) runner, args);
                }
            }
        }

    <16>

        /**
         * 优雅关闭 
         * @param context
         */
        static final SpringApplicationShutdownHook shutdownHook = new SpringApplicationShutdownHook();
        private void refreshContext(ConfigurableApplicationContext context) {
            if (this.registerShutdownHook) {
                shutdownHook.registerApplicationContext(context);
            }
            refresh(context);
        }

     <17>

      private static final String ATTACHED_PROPERTY_SOURCE_NAME = "configurationProperties";
        public static void attach(Environment environment) {
            Assert.isInstanceOf(ConfigurableEnvironment.class, environment);
            //这只是一个门面 内部数组管理多个propertiesSource
            MutablePropertySources sources = ((ConfigurableEnvironment) environment).getPropertySources();
            //获取configurationProperties
            PropertySource<?> attached = getAttached(sources);
            //如果存移除然后插入到头部
            if (attached != null && attached.getSource() != sources) {
                //移除
                sources.remove(ATTACHED_PROPERTY_SOURCE_NAME);
                attached = null;
            }
            //重新放入头部通过ConfigurationPropertySourcesPropertySource 包装 这个内部管理多个SpringConfigurationPropertySources 同时也是根据SpringConfigurationPropertySources包装了一层
            if (attached == null) {
                sources.addFirst(new ConfigurationPropertySourcesPropertySource(ATTACHED_PROPERTY_SOURCE_NAME,
                        new SpringConfigurationPropertySources(sources)));
            }
        }
  • 相关阅读:
    野火书籍《STM32库开发实战指南》配套例程
    使你的MFC程序具有win7的透明立体风格
    C#:params 关键字的学习
    "ASP.NET Ajax 客户端框架未能加载"解决办法
    未能启用约束。一行或多行中包含违反非空、唯一或外键约束的值。
    GIS:如何将东城和崇文合并
    委托和Lambda表达式(一):委托概述
    Cron表达式详解
    正则表达式在JAVA中的简单实例
    使用jdom创建XML文件
  • 原文地址:https://www.cnblogs.com/LQBlog/p/15935244.html
Copyright © 2020-2023  润新知