zoukankan      html  css  js  c++  java
  • spring boot

    @SpringBootApplication

    开启spring boot。
    @SpringBootApplication = @Configuration + @EnableAutoConfaguration + @ComponentScan。
    @EnableAutoConfaguration:表示会自动为依赖的jar包进行配置,比如项目添加了spring-boot-starter-web依赖包,则该注解会自动为项目提供tomcat和spring MVC的配置。
    @ComponentScan:spring会自动对入口类同级及下级包所有的类进行bean管理。

    看一下该注解做了什么

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @SpringBootConfiguration
    @EnableAutoConfiguration//入口
    @ComponentScan(
        excludeFilters = {@Filter(
        type = FilterType.CUSTOM,
        classes = {TypeExcludeFilter.class}
    ), @Filter(
        type = FilterType.CUSTOM,
        classes = {AutoConfigurationExcludeFilter.class}
    )}
    )
    public @interface SpringBootApplication {
        @AliasFor(
            annotation = EnableAutoConfiguration.class,
            attribute = "exclude"
        )
        Class<?>[] exclude() default {};
    
        @AliasFor(
            annotation = EnableAutoConfiguration.class,
            attribute = "excludeName"
        )
        String[] excludeName() default {};
    
        @AliasFor(
            annotation = ComponentScan.class,
            attribute = "basePackages"
        )
        String[] scanBasePackages() default {};
    
        @AliasFor(
            annotation = ComponentScan.class,
            attribute = "basePackageClasses"
        )
        Class<?>[] scanBasePackageClasses() default {};
    }
    
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage//入口
    @Import({EnableAutoConfigurationImportSelector.class})//入口
    public @interface EnableAutoConfiguration {
        String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    
        Class<?>[] exclude() default {};
    
        String[] excludeName() default {};
    }
    
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @Import({Registrar.class})//入口
    public @interface AutoConfigurationPackage {
    }
    
    
    @Order(Ordered.HIGHEST_PRECEDENCE)
    static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
    
        @Override
        public void registerBeanDefinitions(AnnotationMetadata metadata,
                BeanDefinitionRegistry registry) {
              //默认将会扫描@SpringBootApplication标注的主配置类所在的包及其子包下所有组件
            register(registry, new PackageImport(metadata).getPackageName());
        }
    
        @Override
        public Set<Object> determineImports(AnnotationMetadata metadata) {
            return Collections.<Object>singleton(new PackageImport(metadata));
        }
    }
    
    @Deprecated
    public class EnableAutoConfigurationImportSelector extends AutoConfigurationImportSelector {//入口为其父类的selectImports方法
        public EnableAutoConfigurationImportSelector() {
        }
    
        protected boolean isEnabled(AnnotationMetadata metadata) {
            return this.getClass().equals(EnableAutoConfigurationImportSelector.class) ? (Boolean)this.getEnvironment().getProperty("spring.boot.enableautoconfiguration", Boolean.class, true) : true;
        }
    }
    
    //AutoConfigurationImportSelector 
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
            if (!this.isEnabled(annotationMetadata)) {
                return NO_IMPORTS;
            } else {
                try {
                    AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
                    AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
                    //入口
                    List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
                    configurations = this.removeDuplicates(configurations);
                    configurations = this.sort(configurations, autoConfigurationMetadata);
                    Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
                    this.checkExcludedClasses(configurations, exclusions);
                    configurations.removeAll(exclusions);
                    configurations = this.filter(configurations, autoConfigurationMetadata);
                    this.fireAutoConfigurationImportEvents(configurations, exclusions);
                    return (String[])configurations.toArray(new String[configurations.size()]);
                } catch (IOException var6) {
                    throw new IllegalStateException(var6);
                }
            }
        }
    
        protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
            List<String> configurations = 
                    SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());//入口
            return configurations;
        }
    
        public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
            String factoryClassName = factoryClass.getName();
    
            try {
                Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                ArrayList result = new ArrayList();
    
                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
                    String factoryClassNames = properties.getProperty(factoryClassName);
                    result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
                }
    
                return result;
            } catch (IOException var8) {
                throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8);
            }
        }
    
    1. 通过启动注解引入自动配置类
    2. 将主配置类(@SpringBootApplication)所在的包及其子包里面的所有组件扫描到Spring容器中
    3. SpringBoot启动的时候从类路径下的 META-INF/spring.factories中获取EnableAutoConfiguration指定的值,并将这些值作为自动配置类导入到容器中,自动配置类就会生效,最后完成自动配置工作。
      • EnableAutoConfiguration默认在spring-boot-autoconfigure这个包中

    返回顶部

    启动方法

    @SpringBootApplication
    public class HelloWorldMainApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(HelloWorldMainApplication.class, args);
        }
        
    }
    
    // 调用静态类,参数对应的就是HelloWorldMainApplication.class以及main方法中的args
    public static ConfigurableApplicationContext run(Class<?> primarySource,String... args) {
        return run(new Class<?>[] { primarySource }, args);
    }
    public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
        return (new SpringApplication(sources)).run(args);
    }
    
    1. 构造一个SpringApplication的实例,并把我们的启动类HelloWorldMainApplication.class作为参数传进去
    2. 然后运行它的run方法

    接下来分别看一下SpringApplication的构造器和他的run方法

    构造器

    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        //把HelloWorldMainApplication.class设置为属性存储起来
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        //设置应用类型是Standard还是Web
        this.webApplicationType = deduceWebApplicationType();
        //设置初始化器(Initializer),最后会调用这些初始化器
        setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class));
        //设置监听器(Listener)
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = deduceMainApplicationClass();
    }
    
    1. 先将HelloWorldMainApplication.class存储到SpringApplication中
    2. 设置应用类型:非web应用(Standard)还是web应用,我们是web应用
    3. 设置初始化器(Initializer),后续会执行初始化器
    4. 设置监听器(Listener)

    接下来分别详细看一下上面这几步

    返回顶部

    设置应用类型

    private WebApplicationType deduceWebApplicationType() {
        if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
                && !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) {
            return WebApplicationType.REACTIVE;
        }
        for (String className : WEB_ENVIRONMENT_CLASSES) {
            if (!ClassUtils.isPresent(className, null)) {
                return WebApplicationType.NONE;
            }
        }
        return WebApplicationType.SERVLET;
    }
    
    // 相关常量
    private static final String REACTIVE_WEB_ENVIRONMENT_CLASS = "org.springframework."
            + "web.reactive.DispatcherHandler";
    private static final String MVC_WEB_ENVIRONMENT_CLASS = "org.springframework."
            + "web.servlet.DispatcherServlet";
    private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
            "org.springframework.web.context.ConfigurableWebApplicationContext" };
    
    
    
    public enum WebApplicationType {
        NONE,
        SERVLET,
        REACTIVE;
    
        private WebApplicationType() {
        }
    }
    

    返回顶部

    设置初始化器(Initializer)

    //设置初始化器(Initializer),最后会调用这些初始化器
    setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class));
    

    我们先来看看getSpringFactoriesInstances( ApplicationContextInitializer.class)

    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
        return getSpringFactoriesInstances(type, new Class<?>[] {});
    }
    
    // 这里的入参type就是ApplicationContextInitializer.class
    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
            Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        // 使用Set保存names来避免重复元素
        Set<String> names = new LinkedHashSet<>(
                SpringFactoriesLoader.loadFactoryNames(type, classLoader));//入口1
        // 根据names来进行实例化
        List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
                classLoader, args, names);//入口2
        // 对实例进行排序
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }
    
    // 入参就是ApplicationContextInitializer.class
    public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
      String factoryClassName = factoryClass.getName();
    
      try {
          //从类路径的META-INF/spring.factories中加载所有默认的自动配置类
          Enumeration<URL> urls = classLoader != null?classLoader.getResources("META-INF/spring.factories"):ClassLoader.getSystemResources("META-INF/spring.factories");
          ArrayList result = new ArrayList();
    
          while(urls.hasMoreElements()) {
              URL url = (URL)urls.nextElement();
              Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
              //获取ApplicationContextInitializer.class的所有值
              String factoryClassNames = properties.getProperty(factoryClassName);
              result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
          }
    
          return result;
      } catch (IOException var8) {
          throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8);
      }
    }
    
    // parameterTypes: 上一步得到的names集合
    private <T> List<T> createSpringFactoriesInstances(Class<T> type,
            Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
            Set<String> names) {
        List<T> instances = new ArrayList<T>(names.size());
        for (String name : names) {
            try {
                Class<?> instanceClass = ClassUtils.forName(name, classLoader);
                //确认被加载类是ApplicationContextInitializer的子类
                Assert.isAssignable(type, instanceClass);
                Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
                //反射实例化对象
                T instance = (T) BeanUtils.instantiateClass(constructor, args);
                //加入List集合中
                instances.add(instance);
            }
            catch (Throwable ex) {
                throw new IllegalArgumentException(
                        "Cannot instantiate " + type + " : " + name, ex);
            }
        }
        return instances;
    }
    
    1. 从类路径的META-INF/spring.factories中加载所有的初始化器
      • 每个spring.factories会有好多<String,List>格式的配置,取出key为org.springframework.context.ApplicationContextInitializer的value集合
    2. 然后取出这些初始化器的className,存入到集合中
    3. 遍历上面的初始化器集合,通过反射挨个进行实例化,最后加入到list中
    4. 到此,spring boot的初始化器已经被实例化到内存中了,后续等spring容器进行初始化的时候会挨个执行这些初始化器的initialize方法进行初始化。

    返回顶部

    设置监听器(Listener)

    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    
    // 这里的入参type是:org.springframework.context.ApplicationListener.class
    private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) {
        return getSpringFactoriesInstances(type, new Class<?>[] {});
    }
    
    private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
            Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        // Use names and ensure unique to protect against duplicates
        Set<String> names = new LinkedHashSet<String>(
                SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
                classLoader, args, names);
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }
    
    1. 可以发现,这个过程和设置初始化器是一样的,找的是ApplicationListener的实现类。
    2. 到此,实例化了一堆监听器,后续在整个项目的生命周期中,各种事件会被这些监听器监听到

    返回顶部

    run方法

    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);
    
            // 第二步:根据SpringApplicationRunListeners以及参数来准备环境
            ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
            configureIgnoreBeanInfo(environment);
    
            // 准备Banner打印器 - 就是启动Spring Boot的时候打印在console上的ASCII艺术字体
            Banner printedBanner = printBanner(environment);
    
            // 第三步:创建Spring容器
            context = createApplicationContext();
    
            exceptionReporters = getSpringFactoriesInstances(
                    SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
    
            // 第四步:Spring容器前置处理
            prepareContext(context, environment, listeners, applicationArguments,printedBanner);
    
            // 第五步:刷新容器
            refreshContext(context);
    
         // 第六步:Spring容器后置处理
            afterRefresh(context, applicationArguments);
    
          // 第七步:发出结束执行的事件
            listeners.started(context);
            // 第八步:执行Runners
            this.callRunners(context, applicationArguments);
            stopWatch.stop();
            // 返回容器
            return context;
        }
        catch (Throwable ex) {
            handleRunFailure(context, listeners, exceptionReporters, ex);
            throw new IllegalStateException(ex);
        }
    }
    
    1. 第一步:获取并启动启动事件发布器SpringApplicationRunListener
    2. 第二步:根据SpringApplicationRunListeners以及参数来准备环境
    3. 第三步:创建Spring容器
    4. 第四步:Spring容器前置处理
    5. 第五步:刷新容器
    6. 第六步:Spring容器后置处理
    7. 第七步:发出结束执行的事件
    8. 第八步:执行Runners

    返回顶部

    第一步:获取并启动启动事件发布器SpringApplicationRunListener

    获取启动事件发布器

    跟进getRunListeners方法:

    private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
        return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
    }
    
    public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
        private final SpringApplication application;
        private final String[] args;
        //广播器
        private final SimpleApplicationEventMulticaster initialMulticaster;
    
        public EventPublishingRunListener(SpringApplication application, String[] args) {
            this.application = application;
            this.args = args;
            this.initialMulticaster = new SimpleApplicationEventMulticaster();
            Iterator var3 = application.getListeners().iterator();
    
            while(var3.hasNext()) {
                ApplicationListener<?> listener = (ApplicationListener)var3.next();
                //将上面设置到SpringApplication的十一个监听器全部添加到SimpleApplicationEventMulticaster这个广播器中
                this.initialMulticaster.addApplicationListener(listener);
            }
    
        }
        //略...
    }
    
    public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
        //广播器的父类中存放保存监听器的内部内
        private final AbstractApplicationEventMulticaster.ListenerRetriever defaultRetriever = new AbstractApplicationEventMulticaster.ListenerRetriever(false);
    
        @Override
        public void addApplicationListener(ApplicationListener<?> listener) {
            synchronized (this.retrievalMutex) {
                Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
                if (singletonTarget instanceof ApplicationListener) {
                    this.defaultRetriever.applicationListeners.remove(singletonTarget);
                }
                //内部类对象
                this.defaultRetriever.applicationListeners.add(listener);
                this.retrieverCache.clear();
            }
        }
    
        private class ListenerRetriever {
            //保存所有的监听器
            public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet();
            public final Set<String> applicationListenerBeans = new LinkedHashSet();
            private final boolean preFiltered;
    
            public ListenerRetriever(boolean preFiltered) {
                this.preFiltered = preFiltered;
            }
    
            public Collection<ApplicationListener<?>> getApplicationListeners() {
                LinkedList<ApplicationListener<?>> allListeners = new LinkedList();
                Iterator var2 = this.applicationListeners.iterator();
    
                while(var2.hasNext()) {
                    ApplicationListener<?> listener = (ApplicationListener)var2.next();
                    allListeners.add(listener);
                }
    
                if (!this.applicationListenerBeans.isEmpty()) {
                    BeanFactory beanFactory = AbstractApplicationEventMulticaster.this.getBeanFactory();
                    Iterator var8 = this.applicationListenerBeans.iterator();
    
                    while(var8.hasNext()) {
                        String listenerBeanName = (String)var8.next();
    
                        try {
                            ApplicationListener<?> listenerx = (ApplicationListener)beanFactory.getBean(listenerBeanName, ApplicationListener.class);
                            if (this.preFiltered || !allListeners.contains(listenerx)) {
                                allListeners.add(listenerx);
                            }
                        } catch (NoSuchBeanDefinitionException var6) {
                            ;
                        }
                    }
                }
    
                AnnotationAwareOrderComparator.sort(allListeners);
                return allListeners;
            }
        }
        //略...
    }
    
    1. 还是通过上面的方法获取SpringApplicationRunListener,它叫启动事件发布器,也就是在启动后由它来发布启动事件
    2. 第一步通过反射实例化SpringApplicationRunListener的时候,会触发EventPublishingRunListener的构造器
      • EventPublishingRunListener是SpringApplicationRunListener的子类
    3. 定义一个广播器SimpleApplicationEventMulticaster
    4. 将设置监听器阶段实例化的所有监听器都添加到这个广播器中
    5. 到此,我们有一个广播器存储了所有监听器了。这个广播器被启动事件发布器所持有。也就是在启动的时候,启动事件发布器通过它的广播器向所有监听器发布事件。

    启动启动事件发布器

    先来看一下启动事件发布器都定义哪些功能:

    package org.springframework.boot;
    public interface SpringApplicationRunListener {
    
        // 在run()方法开始执行时,该方法就立即被调用,可用于在初始化最早期时做一些工作
        void starting();
        // 当environment构建完成,ApplicationContext创建之前,该方法被调用
        void environmentPrepared(ConfigurableEnvironment environment);
        // 当ApplicationContext构建完成时,该方法被调用
        void contextPrepared(ConfigurableApplicationContext context);
        // 在ApplicationContext完成加载,但没有被刷新前,该方法被调用
        void contextLoaded(ConfigurableApplicationContext context);
        // 在ApplicationContext刷新并启动后,CommandLineRunners和ApplicationRunner未被调用前,该方法被调用
        void started(ConfigurableApplicationContext context);
        // 在run()方法执行完成前该方法被调用
        void running(ConfigurableApplicationContext context);
        // 当应用运行出错时该方法被调用
        void failed(ConfigurableApplicationContext context, Throwable exception);
    }
    
    1. 在Spring Boot启动初始化的过程中各种状态时都定义了接口。我们也可以添加自己的监听器,在SpringBoot初始化时监听事件执行自定义逻辑

    举例看一下启动方法

    @Override
    public void starting() {
        //关键代码,先创建application启动事件`ApplicationStartingEvent`
        this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
    }
    
    @Override
    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        //通过事件类型ApplicationStartingEvent获取对应的监听器
        for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            //获取线程池,如果为空则同步处理。这里线程池为空,还未没初始化。
            Executor executor = getTaskExecutor();
            if (executor != null) {
                //异步发送事件
                executor.execute(() -> invokeListener(listener, event));
            }
            else {
                //同步发送事件
                invokeListener(listener, event);
            }
        }
    }
    
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        //在springboot启动的时候
        if (event instanceof ApplicationStartedEvent) {
            onApplicationStartedEvent((ApplicationStartedEvent) event);
        }
        //springboot的Environment环境准备完成的时候
        else if (event instanceof ApplicationEnvironmentPreparedEvent) {
            onApplicationEnvironmentPreparedEvent(
                    (ApplicationEnvironmentPreparedEvent) event);
        }
        //在springboot容器的环境设置完成以后
        else if (event instanceof ApplicationPreparedEvent) {
            onApplicationPreparedEvent((ApplicationPreparedEvent) event);
        }
        //容器关闭的时候
        else if (event instanceof ContextClosedEvent && ((ContextClosedEvent) event)
                .getApplicationContext().getParent() == null) {
            onContextClosedEvent();
        }
        //容器启动失败的时候
        else if (event instanceof ApplicationFailedEvent) {
            onApplicationFailedEvent();
        }
    }
    
    1. 启动的时候,创建一个事件ApplicationEvent,将其交给启动事件发布器的广播器来处理
    2. 广播器根据事件类型匹配它持有的监听器,进行发布。事件类型有哪些种:
      • ApplicationStartedEvent:在springboot启动的时候
      • ApplicationEnvironmentPreparedEvent:springboot的Environment环境准备完成的时候
      • ApplicationPreparedEvent:在springboot容器的环境设置完成以后
      • ContextClosedEvent:容器关闭的时候
      • ApplicationFailedEvent:容器启动失败的时候

    返回顶部

    第二步:根据启动事件发布器以及参数来准备环境

    private ConfigurableEnvironment prepareEnvironment(
            SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments) {
        //获取对应的ConfigurableEnvironment
        ConfigurableEnvironment environment = getOrCreateEnvironment();//入口1
        //配置
        configureEnvironment(environment, applicationArguments.getSourceArgs());
        //发布环境已准备事件,这是第二次发布事件
        listeners.environmentPrepared(environment);//入口2
        bindToSpringApplication(environment);
        ConfigurationPropertySources.attach(environment);
        return environment;
    }
    
    
    private ConfigurableEnvironment getOrCreateEnvironment() {
        if (this.environment != null) {
            return this.environment;
        }
        if (this.webApplicationType == WebApplicationType.SERVLET) {
            return new StandardServletEnvironment();
        }
        return new StandardEnvironment();
    }
    
    1. 构建Environment
    2. 启动事件发布器再次发布状态变更事件

    返回顶部

    第三步:创建Spring容器

    public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
    protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        if (contextClass == null) {
            try {
                switch (this.webApplicationType) {
                case SERVLET:
                    contextClass = Class.forName(DEFAULT_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);
    }
    
    1. 这一步是实例化spring容器的。根据webApplicationType进行判断,该类型为SERVLET类型,所以会通过反射实例化AnnotationConfigServletWebServerApplicationContext

    返回顶部

    第四步:Spring容器前置处理

    //SpringApplication
    private void prepareContext(ConfigurableApplicationContext context,
            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments, Banner printedBanner) {
        //设置容器环境,包括各种变量
        context.setEnvironment(environment);
        //执行容器后置处理
        postProcessApplicationContext(context);
        //执行容器中的ApplicationContextInitializer(包括 spring.factories和自定义的实例)
        applyInitializers(context);//入口1
      //发送容器已经准备好的事件,通知各监听器
        listeners.contextPrepared(context);
    
        //注册启动参数bean,这里将容器指定的参数封装成bean,注入容器
        context.getBeanFactory().registerSingleton("springApplicationArguments",
                applicationArguments);
        //设置banner
        if (printedBanner != null) {
            context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
        }
        //获取我们的启动类指定的参数,可以是多个
        Set<Object> sources = getAllSources();//入口2
        Assert.notEmpty(sources, "Sources must not be empty");
        //加载我们的启动类,将启动类注入容器
        load(context, sources.toArray(new Object[0]));//入口3
        //发布容器已加载事件。
        listeners.contextLoaded(context);
    }
    
    protected void applyInitializers(ConfigurableApplicationContext context) {
        // 1. 从SpringApplication类中的initializers集合获取所有的ApplicationContextInitializer
        for (ApplicationContextInitializer initializer : getInitializers()) {
            // 2. 循环调用ApplicationContextInitializer中的initialize方法
            Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
                    initializer.getClass(), ApplicationContextInitializer.class);
            Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
            initializer.initialize(context);//入口
        }
    }
    
    public Set<Object> getAllSources() {
        Set<Object> allSources = new LinkedHashSet();
        if (!CollectionUtils.isEmpty(this.primarySources)) {
            //获取primarySources属性,也就是之前存储的HelloWorldMainApplication.class
            allSources.addAll(this.primarySources);
        }
    
        if (!CollectionUtils.isEmpty(this.sources)) {
            allSources.addAll(this.sources);
        }
    
        return Collections.unmodifiableSet(allSources);
    }
    
    protected void load(ApplicationContext context, Object[] sources) {
        BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
        if (this.beanNameGenerator != null) {
            loader.setBeanNameGenerator(this.beanNameGenerator);
        }
        if (this.resourceLoader != null) {
            loader.setResourceLoader(this.resourceLoader);
        }
        if (this.environment != null) {
            loader.setEnvironment(this.environment);
        }
        loader.load();
    }
    
    private int load(Class<?> source) {
        if (isGroovyPresent()
                && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
            // Any GroovyLoaders added in beans{} DSL can contribute beans here
            GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source,
                    GroovyBeanDefinitionSource.class);
            load(loader);
        }
        if (isComponent(source)) {
            //以注解的方式,将启动类bean信息存入beanDefinitionMap,也就是将HelloWorldMainApplication.class存入了beanDefinitionMap
            this.annotatedReader.register(source);
            return 1;
        }
        return 0;
    }
    
    //ConfigurationWarningsApplicationContextInitializer
        public void initialize(ConfigurableApplicationContext context) {
            context.addBeanFactoryPostProcessor(new ConfigurationWarningsApplicationContextInitializer.ConfigurationWarningsPostProcessor(this.getChecks()));
        }
    
    1. 获取之前实例化到内存中的所有初始化器,挨个调用其initialize方法
    2. 我们也可以自定义初始化器,并实现initialize方法,然后放入META-INF/spring.factories配置文件中Key为:org.springframework.context.ApplicationContextInitializer的value中,这里我们自定义的初始化器就会被调用,是我们项目初始化的一种方式
    3. 将启动类HelloWorldMainApplication.class被加载到 beanDefinitionMap中。后续进行bean实例化的时候,会根据这个类的@SpringBootApplication注解完成spring boot的自动配置。
      这一步才是核心功能自动配置的重要桥梁。
      后续要spring容器refresh的时候,遇到HelloWorldMainApplication这个启动类bean,会根据其注解@SpringBootApplication一步一步的找到所有的自动配置类,然后完成自动配置。

    返回顶部

    第五步:刷新容器

    执行到这里,springBoot相关的处理工作已经结束,接下的工作就交给了spring。我们来看看refreshContext(context);

    其实就是spring ioc的refresh方法。

    返回顶部

    第六步:Spring容器后置处理

    扩展接口,设计模式中的模板方法,默认为空实现。如果有自定义需求,可以重写该方法。比如打印一些启动结束log,或者一些其它后置处理。

    返回顶部

    第七步:发出结束执行的事件

    public void started(ConfigurableApplicationContext context) {
        //这里就是获取的EventPublishingRunListener
        Iterator var2 = this.listeners.iterator();
    
        while(var2.hasNext()) {
            SpringApplicationRunListener listener = (SpringApplicationRunListener)var2.next();
            //执行EventPublishingRunListener的started方法
            listener.started(context);
        }
    }
    
    public void started(ConfigurableApplicationContext context) {
        //创建ApplicationStartedEvent事件,并且发布事件
        //我们看到是执行的ConfigurableApplicationContext这个容器的publishEvent方法,和前面的starting是不同的
        context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
    }
    
    1. 创建一个ApplicationStartedEvent事件,获取启动事件发布器,并执行其started方法,并且将创建的Spring容器传进去了
    2. 这里是调用的spring容器进行发布的

    返回顶部

    第八步:执行Runners

    我们再来看看最后一步callRunners(context, applicationArguments);

    private void callRunners(ApplicationContext context, ApplicationArguments args) {
        List<Object> runners = new ArrayList<Object>();
        //获取容器中所有的ApplicationRunner的Bean实例
        runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
        //获取容器中所有的CommandLineRunner的Bean实例
        runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
        AnnotationAwareOrderComparator.sort(runners);
        for (Object runner : new LinkedHashSet<Object>(runners)) {
            if (runner instanceof ApplicationRunner) {
                //执行ApplicationRunner的run方法
                callRunner((ApplicationRunner) runner, args);
            }
            if (runner instanceof CommandLineRunner) {
                //执行CommandLineRunner的run方法
                callRunner((CommandLineRunner) runner, args);
            }
        }
    }
    

    如果是ApplicationRunner的话,则执行如下代码:

    private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
        try {
            runner.run(args);
        } catch (Exception var4) {
            throw new IllegalStateException("Failed to execute ApplicationRunner", var4);
        }
    }
    

    如果是CommandLineRunner的话,则执行如下代码:

    private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
        try {
            runner.run(args.getSourceArgs());
        } catch (Exception var4) {
            throw new IllegalStateException("Failed to execute CommandLineRunner", var4);
        }
    }
    
    1. Runner运行器用于在服务启动时进行一些业务初始化操作,这些操作只在服务启动后执行一次。
      Spring Boot提供了ApplicationRunner和CommandLineRunner两种服务接口CommandLineRunner、ApplicationRunner

    返回顶部

  • 相关阅读:
    Java 数组
    【转】Centos 设置IP地址的几种方式
    【转】CentOS 使用yum命令安装出现错误提示”could not retrieve mirrorlist http://mirrorlist.centos.org ***”
    【转】CentOS图形界面的开启与关闭
    【转】linux Centos 6.5 安装桌面环境GNOME
    VirtualBox 更改主机和虚拟机之间的鼠标切换热键
    【转】Virtualbox虚拟机配置安装CentOS 6.5图文教程
    0622 python 基础05
    0617 python 基础04
    0610 python 基础03
  • 原文地址:https://www.cnblogs.com/yanhui007/p/12595648.html
Copyright © 2011-2022 走看看