zoukankan      html  css  js  c++  java
  • SpringBoot启动过程原理

    最近这两年springboot突然火起来了,那么我们就来看看springboot的运行原理。

    一。springboot的三种启动方式:

    1.运行带有main方法的
    2.通过命令 Java -jar命令
    3.通过spring-boot-plugin的方式

    二。springboot 启动时执行方法,有两种方式

    第一种方式是用启动时的main方法加载静态方法。

    另一种是用初始化注解@postconstruct 执行。(注意点必须void并且参数)。

    注意点:【1.@PostConstruct会先被执行,静态方法后被执行。2.如果需要参数的话,只能用静态方法的方式

    SpringBoot启动过程原理

    从上面代码看,调用了SpringApplication的静态方法run。这个run方法会构造一个SpringApplication的实例,然后再调用这里实例的run方法就表示启动SpringBoot。

    具体对象处理流程看下边时序图:

    概述:

    1.构造SpringApplication的实例(时序图步骤1-2)
    2.调用SpringApplication.run()方法(时序图步骤3)
    3.构造SpringApplicationRunListeners 实例(时序图步骤3.1.1)
    4.发布ApplicationStartedEvent事件(时序图步骤3.1.2)
    5.SpringApplicationRunListeners 实例准备环境信息(时序图步骤3.1.3)
    6.创建ApplicationContext对象(时序图步骤3.1.4)
    7.ApplicationContext实例准备环境信息(时序图步骤3.1.5)
    8.刷新的上下文(时序图步骤3.1.6)

    2.启动加载过程分析

    1.2.1 构造SpringApplication的实例(时序图步骤1-2)
    代码
    
    public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
            // 步骤1
            return new SpringApplication(sources).run(args);
    }
    public SpringApplication(Object... sources) {
            // 步骤1.1
            initialize(sources);
    }
    @SuppressWarnings({ "unchecked", "rawtypes" })
        private void initialize(Object[] sources) {
            if (sources != null && sources.length > 0) {
                this.sources.addAll(Arrays.asList(sources));
            }
            this.webEnvironment = deduceWebEnvironment();
            //加载META-INF/spring.factories路径ApplicationContextInitializer.class
            getSpringFactoriesInstances(
                    ApplicationContextInitializer.class));
            setListeners((Collection) 
            //加载META-INF/spring.factories路径ApplicationListener.class
            getSpringFactoriesInstances(ApplicationListener.class));
            this.mainApplicationClass = deduceMainApplicationClass();
        }

    分析
    ⑴.通过ClassLoader.getResources加载META-INF/spring.factories路径下的
    文件信息,从中找key为ApplicationContextInitializer.class,并实例化。
    ⑵.通过ClassLoader.getResources加载META-INF/spring.factories路径下的
    文件信息ApplicationListener.class对应类,并实例化。

    1.2.2 调用SpringApplication.run()方法(时序图步骤3)
    代码:
    
    public ConfigurableApplicationContext run(String... args) {
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            ConfigurableApplicationContext context = null;
            FailureAnalyzers analyzers = null;
            configureHeadlessProperty();
            //  步骤3.1.1
            SpringApplicationRunListeners listeners = getRunListeners(args);
            // 步骤3.1.2
            listeners.starting();
            try {
                ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                        args);
                // 步骤 3.1.3
                ConfigurableEnvironment environment = prepareEnvironment(listeners,
                        applicationArguments);
                Banner printedBanner = printBanner(environment);
                // 步骤3.1.4
                context = createApplicationContext();
                analyzers = new FailureAnalyzers(context);
                // 步骤3.1.5
                prepareContext(context, environment, listeners, applicationArguments,
                        printedBanner);
                // 步骤3.1.6
                refreshContext(context);
                // 步骤3.1.7
                afterRefresh(context, applicationArguments);
                // 步骤3.1.8
                listeners.finished(context, null);
                stopWatch.stop();
                if (this.logStartupInfo) {
                    new StartupInfoLogger(this.mainApplicationClass)
                            .logStarted(getApplicationLog(), stopWatch);
                }
                return context;
            }
            catch (Throwable ex) {
                handleRunFailure(context, listeners, analyzers, ex);
                throw new IllegalStateException(ex);
            }
        }
    1.2.2 步骤3.1.1:
    代码
    
    private SpringApplicationRunListeners getRunListeners(String[] args) {
            Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
            // (1)
            return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
                    SpringApplicationRunListener.class, types, this, args));
        }
    1
    2
    3
    4
    5
    6
    分析 
    (1). 通过ClassLoader.getResources加载META-INF/spring.factories路径下的 
    文件信息,从中找key为SpringApplicationRunListener对应类,并实例化。
    1.2.3 步骤3.1.2:
    代码
    
    public void starting() {
            for (SpringApplicationRunListener listener : this.listeners) {
                listener.starting();
            }
        }
        @Override
        @SuppressWarnings("deprecation")
        public void starting() {
            this.initialMulticaster
                    .multicastEvent(new ApplicationStartedEvent(this.application, this.args));
        }

    分析 
    :发布ApplicationStartedEvent事件。

    1.2.4 步骤3.1.3:
    代码
    
    private ConfigurableEnvironment prepareEnvironment(
                SpringApplicationRunListeners listeners,
                ApplicationArguments applicationArguments) {
            // Create and configure the environment
            // ⑴. 得到环境对象ConfigurableEnvironment
            ConfigurableEnvironment environment = getOrCreateEnvironment();
            // ⑵. 并配置环境信息;对listeners初始化环境属性
            configureEnvironment(environment, applicationArguments.getSourceArgs());
            // ⑶. 发布ApplicationEnvironmentPreparedEvent事件。
            listeners.environmentPrepared(environment);
            if (isWebEnvironment(environment) && !this.webEnvironment) {
                environment = convertToStandardEnvironment(environment);
            }
            return environment;
        }

    分析 
    ⑴. 得到环境对象ConfigurableEnvironment 
    ⑵. 并配置环境信息;对listeners初始化环境属性。 
    ⑶. 发布ApplicationEnvironmentPreparedEvent事件。

    步骤3.1.4:
    分析 
    创建ApplicationContext对象 ,其中在实例化ApplicationContext子类 
    AnnotationConfigApplicationContext时,如代码:
    
    public AnnotationConfigApplicationContext() {
    this.reader = new AnnotatedBeanDefinitionReader(this);
    this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

    会创建AnnotatedBeanDefinitionReader对象检测是否需要将一下对象放到Spring上下文中

    // 用户配置Configuration注解,实现了BeanDefinitionRegistryPostProcessor接口
    ConfigurationClassPostProcessor
    // 用于配置Autowired注解,实现了MergedBeanDefinitionPostProcessor接口
    AutowiredAnnotationBeanPostProcessor
    // 用于配置Required注解,实现了MergedBeanDefinitionPostProcessor接口
    RequiredAnnotationBeanPostProcessor
    // 用于配置JSR-250注解,实现了InstantiationAwareBeanPostProcessor接口
    CommonAnnotationBeanPostProcessor
    // 用于配置JPA注解
    PersistenceAnnotationBeanPostProcessor
    // 用于配置EventListener注解,实现了SmartInitializingSingleton接口
    EventListenerMethodProcessor
    // EventListener工厂
    DefaultEventListenerFactory
    步骤3.1.5:
    代码
    
    private void prepareContext(ConfigurableApplicationContext context,
                ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
                ApplicationArguments applicationArguments, Banner printedBanner) {
            // ⑴.对ApplicationContext设置环境变量;
            context.setEnvironment(environment);
            // ⑵.配置属性ResourceLoader和ClassLoader属性;
            postProcessApplicationContext(context);
            // ⑶.循环初始化继承了
            applyInitializers(context);
            listeners.contextPrepared(context);
            if (this.logStartupInfo) {
                logStartupInfo(context.getParent() == null);
                logStartupProfileInfo(context);
            }
    
            // Add boot specific singleton beans
            context.getBeanFactory().registerSingleton("springApplicationArguments",
                    applicationArguments);
            if (printedBanner != null) {
                context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
            }
    
            // Load the sources
            Set<Object> sources = getSources();
            Assert.notEmpty(sources, "Sources must not be empty");
            load(context, sources.toArray(new Object[sources.size()]));
            listeners.contextLoaded(context);
        }

    分析: 
    ⑴.对ApplicationContext设置环境变量; 
    ⑵.配置属性ResourceLoader和ClassLoader属性; 
    ⑶.调用步骤1查询出来ApplicationContextInitializer子类,循环调用initialize()方法。

    @SuppressWarnings({ "rawtypes", "unchecked" })
        protected void applyInitializers(ConfigurableApplicationContext context) {
            for (ApplicationContextInitializer initializer : getInitializers()) {
                Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
                        initializer.getClass(), ApplicationContextInitializer.class);
                Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
                initializer.initialize(context);
            }
        }

    ⑷.发布ApplicationPreparedEvent事件。

    步骤3.1.6
    代码:
    
    @Override
        public void refresh() throws BeansException, IllegalStateException {
            synchronized (this.startupShutdownMonitor) {
                // ⑴.准备刷新的上下文环境
                prepareRefresh();
    
                // ⑵.初始化BeanFactory
                ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
                // ⑶.对BeanFactory进行各种功能填充
                prepareBeanFactory(beanFactory);
    
                try {
                    // ⑷.子类覆盖方法做额外的处理
                    postProcessBeanFactory(beanFactory);
    
                    // ⑸.激活各种BeanFactory处理器
                    invokeBeanFactoryPostProcessors(beanFactory);
    
                    // ⑹.注册拦截Bean创建的Bean处理,这里只是注册,真正调用是再拿去Bean的时候
                    registerBeanPostProcessors(beanFactory);
    
                    // ⑺.为上下文初始化Message源,即不同语言的消息体,国际化处理
                    initMessageSource();
    
                    // ⑻.初始化应用消息广播器,并放到applicationEventMulticaster bean中
                    initApplicationEventMulticaster();
    
                    // ⑼.留给子类来初始化其他bean
                    onRefresh();
    
                    // ⑽.在所有注册的bean中查找Listener bean,注册到消息广播中
                    registerListeners();
    
                    // ⑾.初始化剩下的单实例(非惰性)
                    finishBeanFactoryInitialization(beanFactory);
    
                    // ⑿.完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出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...
                    resetCommonCaches();
                }
            }
        }

    分析:

    ⑴.准备刷新的上下文环境
    ⑵.初始化BeanFactory
    ⑶.对BeanFactory进行各种功能填充
    ⑷.子类覆盖方法做额外的处理
    ⑸.激活各种BeanFactory处理器
    ⑹.注册拦截Bean创建的Bean处理,这里只是注册,真正调用是再拿去Bean的时候
    ⑺.为上下文初始化Message源,即不同语言的消息体,国际化处理
    ⑻.初始化应用消息广播器,并放到applicationEventMulticaster bean中
    ⑼.留给子类来初始化其他bean
    ⑽.在所有注册的bean中查找Listener bean,注册到消息广播中
    ⑾.初始化剩下的单实例(非惰性)
    ⑿.完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人

    总结:

    Spring 是一个“引擎” 
    Spring MVC 是基于 Spring 的一个 MVC 框架 
    Spring Boot 是基于 Spring4 的条件注册的一套快速开发整合包 

    Spring 最初利用“工厂模式”( DI )和“代理模式”( AOP )解耦应用组件,并构建了一些列功能组件。大家觉得挺好用,于是按照 MVC 框架模式,(用Spring 解耦的组件)搞了一个MVC用来开发 web 应用也就是( SpringMVC )。然后有发现每次开发都要搞很多依赖,写很多样板代码很麻烦,于是搞了一些懒人整合包( starter ),这套就是 Spring Boot 。  
    spring 框架有超多的延伸产品例如 boot security jpa etc... 但它的基础就是 spring 的 ioc 和 aop ioc 提供了依赖注入的容器 aop 解决了面向横切面的编程 然后在此两者的基础上实现了其他延伸产品的高级功能 Spring MVC 呢是基于 Servlet 的一个 MVC 框架 主要解决 WEB 开发的问题 因为 Spring 的配置太复杂了 各种 XML JavaConfig hin 麻烦 于是懒人改变世界推出了 Spring boot 约定优于配置 简化了 spring 的配置流程 简单谈下自己的理解   以上来自度娘,感觉和自己的理解相当。直接拿来用,占个坑。以后完善。

    springApplication可以读取不同种类的源文件:

    • 类- java类由AnnotatedBeanDefinitionReader加载。
    • Resource - xml资源文件由XmlBeanDefinitionReader读取, 或者groovy脚本由GroovyBeanDefinitionReader读取
    • Package - java包文件由ClassPathBeanDefinitionScanner扫描读取。
    • CharSequence - 字符序列可以是类名、资源文件、包名,根据不同方式加载。如果一个字符序列不可以解析程序到类,也不可以解析到资源文件,那么就认为它是一个包。
  • 相关阅读:
    C#的GroupBy方法是如何工作的
    流媒体技术探索(一)
    战争雷霆-鼠标穿透
    继承与ER图
    从零开始的文档对象模型(结束更新)
    [hackerrank] booking.com
    [lintcode][美国大公司][1.字符串处理]
    [interview] Aug. 2015
    [codility] Lesson 2 Counting Elements
    [codility] Lesson 1 Time Complexity
  • 原文地址:https://www.cnblogs.com/huojg-21442/p/10489792.html
Copyright © 2011-2022 走看看