面试九、springboot

1、springboot本身并不提供spring框架的核心特性以及扩展功能

  只是用于更敏捷、快速的开发基于spring框架的应用程序。

  重点:

  springboot通过@EnableAutoConfiguration开启自动装配,通过SpringFactoriesLoader加载

  META-INF/spring.factories中的自动配置类实现自动装配

2、优点:

  1)自动配置

  2)提供推荐的基础pom来简化maven配置

  3)提供性能指标、应用健康检查等功能

  4)没有xml配置

3、启动类相关注解

@SpringBootApplication(exclude = {FeignAutoConfiguration.class})
// 自定义要扫描的路径
@ComponentScan(basePackages = {"com.jijc.app","com.jijc.base.mq"})
// mybatis用
@MapperScan(basePackages = {"com.jijc.app.*.dao","com.jijc.base.mq.dao"})
public class DemoBootApplication {

    public static void main(String[] args) {
        SpringApplication.run(new Class[]{
                ApplicationFailedEventListener.class,
                DemoBootApplication.class
        }, args);
    }

}

  3.1、@SpringBootApplication:是一个复合注解,代码如下

1 @Target(ElementType.TYPE)
2 @Retention(RetentionPolicy.RUNTIME)
3 @Documented
4 @Inherited
5 @SpringBootConfiguration
6 @EnableAutoConfiguration
7 @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
8         @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
9 public @interface SpringBootApplication {}

    @SpringBootConfiguration:有了这个注解,我们可以把由@SpringBootApplition注解

      修饰的类当作配置类来使用,即在类DemoBootApplication中由@Bean注解修饰的

      代码都会被注入到IOC容器由spring来管理。

1 @Target(ElementType.TYPE)
2 @Retention(RetentionPolicy.RUNTIME)
3 @Documented
4 @Configuration
5 public @interface SpringBootConfiguration {}

    @ComponentScan:此注解会自动扫描指定包下的类,将其注入IOC容器交spring管理

    @EnableAutoConfiguration:用于导入自动配置类

1 @Target(ElementType.TYPE)
2 @Retention(RetentionPolicy.RUNTIME)
3 @Documented
4 @Inherited
5 @AutoConfigurationPackage
6 @Import(AutoConfigurationImportSelector.class)
7 public @interface EnableAutoConfiguration {}

    @Import:此注解可以导入三种类

      1)由@Configuration注解修饰的类

      2)ImportSelector或InportBeanDefinitionRegistrar的实现类

      3)普通的组件类,即由@Component注解修饰的类

    注:由上可知springboot中自动配置的加载使用的是AutoConfigurationImportSelector

4、启动过程

  4.1、SpringApplication.run():创建了一个SpringApplication,再调用实例run方法

 1     /**
 2      * Static helper that can be used to run a {@link SpringApplication} from the
 3      * specified sources using default settings and user supplied arguments.
 4      * @param primarySources the primary sources to load
 5      * @param args the application arguments (usually passed from a Java main method)
 6      * @return the running {@link ApplicationContext}
 7      */
 8     public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
 9         return new SpringApplication(primarySources).run(args);
10     }

  4.2、创建SpringApplication实例代码

    13行:resourceLoader提供资源导入,从上面代码可以此处传入为null

    15行:此处为DemoBootApplication.class

    16行:判断应用是standard还是web

    17行:设置初始化器Initializers

      getSpringFactoriesInstances(ApplicationContextInitializer.class):

        从类路径的META-INF/spring.factories处读取相应配置文件,

        遍历读取配置中key为org.springframework.context.ApplicationContextInitializer的value

        value是一系列类名

      setInitializers():

        将这些类名放入springApplication里

    18行:设置监听器listener:方法和设置初始化器一致

      getSpringFactoriesInstances(ApplicationListener.class):

        从类路径的META-INF/spring.factories处读取相应配置文件,

        遍历读取配置中key为org.springframework.context.ApplicationListener的value

        value是一系列类名

      setListeners():

        将这些类名放入springApplication里

    19行:获取入口类的信息

    

 1     /**
 2      * Create a new {@link SpringApplication} instance. The application context will load
 3      * beans from the specified primary sources (see {@link SpringApplication class-level}
 4      * documentation for details. The instance can be customized before calling
 5      * {@link #run(String...)}.
 6      * @param resourceLoader the resource loader to use
 7      * @param primarySources the primary bean sources
 8      * @see #run(Class, String[])
 9      * @see #setSources(Set)
10      */
11     @SuppressWarnings({ "unchecked", "rawtypes" })
12     public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
13         this.resourceLoader = resourceLoader;
14         Assert.notNull(primarySources, "PrimarySources must not be null");
15         this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
16         this.webApplicationType = WebApplicationType.deduceFromClasspath();
17         setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
18         setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
19         this.mainApplicationClass = deduceMainApplicationClass();
20     }

  4.3、run启动

    8行:启动计时工具

    12行:设置java.awt.headless为true,没有图形化界面

    13行:获取SpringApplicationRunListeners

      内部调用getSpringFactoriesInstances(SpringApplicationRunListener.class):

        从类路径的META-INF/spring.factories处读取相应配置文件,

        遍历读取配置中key为org.springframework.context.SpringApplicationRunListener的value

        value是一系列类名

      SpringApplicationEvent:它会利用一个内部的ApplicationEventMulticaster在上下文实际

        被刷新之前对事件进行处理,它实际上是一个事件中转器,它能够感知到Spring Boot启动

        过程中产生的事件,然后有选择性的将事件进行中转

    14行:发出开始执行事件

    17行:根据SpringApplicationRunListener和参数来准备环境

    19行:准备banner打印器-就是springboot启动时打印出来的艺术字

    20行:创建上下文,根据之前获得的应用类型创建对应的上下文

    21行:同理获取SpringBootExceptionReporters

    23行:上下文前置处理,内部会执行每个initializer的initialize(),完成初始化

    24行:上下文刷新

    25行:上下文后置处理

    26行:计时器结束

    29行:发出启动完成事件

    39行:发出运行中事件

 1     /**
 2      * Run the Spring application, creating and refreshing a new
 3      * {@link ApplicationContext}.
 4      * @param args the application arguments (usually passed from a Java main method)
 5      * @return a running {@link ApplicationContext}
 6      */
 7     public ConfigurableApplicationContext run(String... args) {
 8         StopWatch stopWatch = new StopWatch();
 9         stopWatch.start();
10         ConfigurableApplicationContext context = null;
11         Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
12         configureHeadlessProperty();
13         SpringApplicationRunListeners listeners = getRunListeners(args);
14         listeners.starting();
15         try {
16             ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
17             ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
18             configureIgnoreBeanInfo(environment);
19             Banner printedBanner = printBanner(environment);
20             context = createApplicationContext();
21             exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
22                     new Class[] { ConfigurableApplicationContext.class }, context);
23             prepareContext(context, environment, listeners, applicationArguments, printedBanner);
24             refreshContext(context);
25             afterRefresh(context, applicationArguments);
26             stopWatch.stop();
27             if (this.logStartupInfo) {
28                 new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
29             }
30             listeners.started(context);
31             callRunners(context, applicationArguments);
32         }
33         catch (Throwable ex) {
34             handleRunFailure(context, ex, exceptionReporters, listeners);
35             throw new IllegalStateException(ex);
36         }
37 
38         try {
39             listeners.running(context);
40         }
41         catch (Throwable ex) {
42             handleRunFailure(context, ex, exceptionReporters, null);
43             throw new IllegalStateException(ex);
44         }
45         return context;
46     }

    其他关键方法:

    prepareContext:准备环境

      5行:遍历准备好的Initailizers,调用initalize()初始化

 1 private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
 2             SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
 3         context.setEnvironment(environment);
 4         postProcessApplicationContext(context);
 5         applyInitializers(context);
 6         listeners.contextPrepared(context);
 7         if (this.logStartupInfo) {
 8             logStartupInfo(context.getParent() == null);
 9             logStartupProfileInfo(context);
10         }
11         // Add boot specific singleton beans
12         ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
13         beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
14         if (printedBanner != null) {
15             beanFactory.registerSingleton("springBootBanner", printedBanner);
16         }
17         if (beanFactory instanceof DefaultListableBeanFactory) {
18             ((DefaultListableBeanFactory) beanFactory)
19                     .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
20         }
21         if (this.lazyInitialization) {
22             context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
23         }
24         // Load the sources
25         Set<Object> sources = getAllSources();
26         Assert.notEmpty(sources, "Sources must not be empty");
27         load(context, sources.toArray(new Object[0]));
28         listeners.contextLoaded(context);
29     }
30 
31 @Override
32     public void refresh() throws BeansException, IllegalStateException {
33         synchronized (this.startupShutdownMonitor) {
34             // Prepare this context for refreshing.
35             prepareRefresh();
36 
37             // Tell the subclass to refresh the internal bean factory.
38             ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
39 
40             // Prepare the bean factory for use in this context.
41             prepareBeanFactory(beanFactory);
42 
43             try {
44                 // Allows post-processing of the bean factory in context subclasses.
45                 postProcessBeanFactory(beanFactory);
46 
47                 // Invoke factory processors registered as beans in the context.
48                 invokeBeanFactoryPostProcessors(beanFactory);
49 
50                 // Register bean processors that intercept bean creation.
51                 registerBeanPostProcessors(beanFactory);
52 
53                 // Initialize message source for this context.
54                 initMessageSource();
55 
56                 // Initialize event multicaster for this context.
57                 initApplicationEventMulticaster();
58 
59                 // Initialize other special beans in specific context subclasses.
60                 onRefresh();
61 
62                 // Check for listener beans and register them.
63                 registerListeners();
64 
65                 // Instantiate all remaining (non-lazy-init) singletons.
66                 finishBeanFactoryInitialization(beanFactory);
67 
68                 // Last step: publish corresponding event.
69                 finishRefresh();
70             }
71 
72             catch (BeansException ex) {
73                 if (logger.isWarnEnabled()) {
74                     logger.warn("Exception encountered during context initialization - " +
75                             "cancelling refresh attempt: " + ex);
76                 }
77 
78                 // Destroy already created singletons to avoid dangling resources.
79                 destroyBeans();
80 
81                 // Reset 'active' flag.
82                 cancelRefresh(ex);
83 
84                 // Propagate exception to caller.
85                 throw ex;
86             }
87 
88             finally {
89                 // Reset common introspection caches in Spring's core, since we
90                 // might not ever need metadata for singleton beans anymore...
91                 resetCommonCaches();
92             }
93         }
94     }

 

5、SpringApplication实例的构建过程

  其中主要涉及到了初始化器(Initializer)以及监听器(Listener)这两大概念

  它们都通过META-INF/spring.factories完成定义。

6、SpringApplication实例run方法的执行过程

  其中主要有一个SpringApplicationRunListener

  它作为SpringBoot容器初始化时各阶段事件的中转器,

  将事件派发给感兴趣的Listeners(在SpringApplication实例化中得到),

  这些阶段性事件将容器的初始化过程给构造起来。

 

 

    

posted on 2021-09-01 16:42  Iversonstear  阅读(41)  评论(0编辑  收藏  举报

导航