当前位置:   article > 正文

Spring boot 启动源码

Spring boot 启动源码

1、main启动:

    @SpringBootApplication + SpringApplication.run(App.class,args)

  1. @SpringBootApplication
  2. public class App {
  3. public static void main(String[] args) {
  4. SpringApplication.run(App.class,args);
  5. }
  6. }

spring boot分析@SpringBootApplication注解@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan

1.1、@SpringBootConfiguration定义当前为配置类

1.2、@ComponentScan指定扫描哪些范围

1.3、@EnableAutoConfiguration:@AutoConfigurationPackage + @Import(AutoConfigurationImportSelector.class)

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

    1.3.1、@AutoConfigurationPackage:@Import(AutoConfigurationPackages.Registrar.class)

            new PackageImports(metadata).getPackageNames()获取主程序包名,所以spring boot默认扫描主程序所在包下所有配置注入到Bean

  1. static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
  2. //导入组件
  3. @Override
  4. public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
  5. register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
  6. }
  7. @Override
  8. public Set<Object> determineImports(AnnotationMetadata metadata) {
  9. return Collections.singleton(new PackageImports(metadata));
  10. }
  11. }

    1.3.2、 @Import(AutoConfigurationImportSelector.class)

            1)、selectImports获取导入组件

  1. @Override
  2. public String[] selectImports(AnnotationMetadata annotationMetadata) {
  3. if (!isEnabled(annotationMetadata)) {
  4. return NO_IMPORTS;
  5. }
  6. AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
  7. return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
  8. }

            2)、getAutoConfigurationEntry获取所有需要组件

  1. protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
  2. if (!isEnabled(annotationMetadata)) {
  3. return EMPTY_ENTRY;
  4. }
  5. AnnotationAttributes attributes = getAttributes(annotationMetadata);
  6. List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
  7. configurations = removeDuplicates(configurations);
  8. Set<String> exclusions = getExclusions(annotationMetadata, attributes);
  9. checkExcludedClasses(configurations, exclusions);
  10. configurations.removeAll(exclusions);
  11. configurations = getConfigurationClassFilter().filter(configurations);
  12. fireAutoConfigurationImportEvents(configurations, exclusions);
  13. return new AutoConfigurationEntry(configurations, exclusions);
  14. }

            3)、getCandidateConfigurations获取所有要导入的候选组件

  1. protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
  2. List<String> configurations = new ArrayList<>(
  3. SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));
  4. ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);
  5. Assert.notEmpty(configurations,
  6. "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you "
  7. + "are using a custom packaging, make sure that file is correct.");
  8. return configurations;
  9. }

其中spring boot 2.7.3后已经不建议SpringFactoriesLoader.loadFactoryNames

            4)、SPI机制META-INF/spring/%s.imports中的组件

  1. public static ImportCandidates load(Class<?> annotation, ClassLoader classLoader) {
  2. Assert.notNull(annotation, "'annotation' must not be null");
  3. ClassLoader classLoaderToUse = decideClassloader(classLoader);
  4. String location = String.format(LOCATION, annotation.getName());
  5. Enumeration<URL> urls = findUrlsInClasspath(classLoaderToUse, location);
  6. List<String> importCandidates = new ArrayList<>();
  7. while (urls.hasMoreElements()) {
  8. URL url = urls.nextElement();
  9. importCandidates.addAll(readCandidateConfigurations(url));
  10. }
  11. return new ImportCandidates(importCandidates);
  12. }

        5)、EnableAutoConfiguration从META-INF/spring.factories移到org.springframework.boot.autoconfigure.AutoConfiguration.imports

分析 SpringApplication类,提供静态方法调用构造方法实现方法调用

  1. public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
  2. return run(new Class<?>[] { primarySource }, args);
  3. }
  4. public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
  5. return new SpringApplication(primarySources).run(args);
  6. }
启动方法SpringApplication.run(App.class,args)可以写成new SpringApplication(App.class).run(args)
2、初始化
启动环境变量准备、资源构造器初始化
  1. public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
  2. this.resourceLoader = resourceLoader;
  3. Assert.notNull(primarySources, "PrimarySources must not be null");
  4. this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
  5. this.webApplicationType = WebApplicationType.deduceFromClasspath();
  6. this.bootstrapRegistryInitializers = new ArrayList<>(
  7. getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
  8. //实例化META-INF/spring.factories 相应初始化器
  9. setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
  10. //实例化监听器
  11. setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
  12. this.mainApplicationClass = deduceMainApplicationClass();
  13. }

2.1、setInitializers,实例化所有初始器:

    事件流程:

  1. # Application Context Initializers
  2. org.springframework.context.ApplicationContextInitializer=\
  3. org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
  4. org.springframework.boot.context.ContextIdApplicationContextInitializer,\
  5. org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
  6. org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
  7. org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer

    2.1.1、扩展:增加自定义初始化器

    1)、新增自定义初始化类,实现ApplicationContextInitializer类,重写initialize方法

  1. public class MyInitializer implements ApplicationContextInitializer {
  2. @Override
  3. public void initialize(ConfigurableApplicationContext applicationContext) {
  4. System.out.println("自定义初始化执行器");
  5. ConfigurableEnvironment environment = applicationContext.getEnvironment();
  6. Map proMap = new HashMap<>();
  7. proMap.put("key","myinitializer");
  8. proMap.put("value","sk");
  9. environment.getPropertySources().addLast(new MapPropertySource("MyInitailizer",proMap));
  10. System.out.println("初始化结束,添加参数!");
  11. }
  12. }

    2)、SPI配置resources/META-INF/spring.factories增加Initializers定义

  1. # Application Context Initializers
  2. org.springframework.context.ApplicationContextInitializer=\
  3. com.sk.cloud.spring.init.initialner.MyInitializer

    3)、调试如下

    4)、调用链路:SpringApplication#run()->prepareContext(..)-->applyInitializers(context)-initialize(context)-->回调自定义初始化器

2.2、setListeners,实例化所有监听器

    监听机制:

    事件流程:

  1. # Application Listeners
  2. org.springframework.context.ApplicationListener=\
  3. org.springframework.boot.ClearCachesApplicationListener,\
  4. org.springframework.boot.builder.ParentContextCloserApplicationListener,\
  5. org.springframework.boot.context.FileEncodingApplicationListener,\
  6. org.springframework.boot.context.config.AnsiOutputApplicationListener,\
  7. org.springframework.boot.context.config.DelegatingApplicationListener,\
  8. org.springframework.boot.context.logging.LoggingApplicationListener,\
  9. org.springframework.boot.env.EnvironmentPostProcessorApplicationListener

        2.2.1、扩展:增加自定义监视器(开始和结束监听器)

            1)、创建自定义监听器,实现

  1. public class AppStartingListener implements ApplicationListener<ApplicationStartingEvent> {
  2. @Override
  3. public void onApplicationEvent(ApplicationStartingEvent event) {
  4. System.out.println("容器启动前");
  5. }
  6. }
  7. public class AppEndListener implements ApplicationListener<ApplicationStartedEvent> {
  8. @Override
  9. public void onApplicationEvent(ApplicationStartedEvent event) {
  10. System.out.println("容器启动后");
  11. }
  12. }

            2)、SPI配置resources/META-INF/spring.factories增加Listeners定义

  1. # Application Listeners
  2. org.springframework.context.ApplicationListener=\
  3. com.sk.cloud.spring.init.listenter.AppEndListener,\
  4. com.sk.cloud.spring.init.listenter.AppStartingListener

        3)、调试如下

        4)、监听器回调

                

                    1)、ApplicationStartingEvent事件回调:SpringApplication#run() --> listeners.starting(..)  -->回调

                    2)、ApplicationStartedEvent事件回调:SpringApplication#run() --> listeners.started(..) --> 回调

   2.3、prepareEnvironment:准备Environment环境对象

  url:Springboot配置文件加载原理及流程【源码分析】_springboot加载配置文件源码-CSDN博客

    2.4、上下文刷新

        1)、确定context类型

  1. context = createApplicationContext();
  2. public enum WebApplicationType {
  3. /**
  4. * The application should not run as a web application and should not start an
  5. * embedded web server.
  6. * 不启动内嵌的WebServer,不是运行web application
  7. */
  8. NONE,
  9. /**
  10. * The application should run as a servlet-based web application and should start an
  11. * embedded servlet web server.
  12. * 启动内嵌的基于servlet的web server
  13. */
  14. SERVLET,
  15. /**
  16. * The application should run as a reactive web application and should start an
  17. * embedded reactive web server.
  18. * 启动内嵌的reactive web server,这个application是一个reactive web application
  19. */
  20. REACTIVE;
  21. }

        2)、prepareContext :预加载

        Bean注册到单例池 --> SPI机制初始化ApplicationContextInitializer列表 --> 广播ApplicationContextInitializedEvent事件 --> 打印启动容器(Starting App ...)--> load(启动类转化为BeanDefinition注册到spring容器的BeanDefinitionMap中) --> listeners.contextLoaded(context)遍历了SpringApplication对象所有的监听器(创建SpringApplication的时候,从META-INF/spring.factories中加载到的ApplicationListener),判断实现ApplicationContextAware接口添加到spring容器的监听列表。最后广播ApplicationPreparedEvent事件添加到spring容器中

    2.5、refreshContext

         refreshContext(..)-->AbstractApplicationContext#refresh

  1. public void refresh() throws BeansException, IllegalStateException {
  2. //上下文刷新前的准备工作:设置启动日期、context当前状态、初始化属性和环境
  3. prepareRefresh();
  4. //获取bean工厂类
  5. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
  6. //配置beanFactory一些特性,例如上下类加载器和后处理器
  7. prepareBeanFactory(beanFactory);
  8. try {
  9. postProcessBeanFactory(beanFactory);
  10. StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
  11. // 执行beanFactory后置处理器,可以自定义BeanFactoryPostProcessor修改Bean属性值
  12. //ConfigurationClassParser#doProcessConfigurationClass 解析所有beanDefinition(配置类、bean类)
  13. invokeBeanFactoryPostProcessors(beanFactory);
  14. //注册bean的PostProcessor,用于后续bean的创建和拦截:自定义BeanPostProcessor实现postProcessBeforeInitialization和postProcessAfterInitialization拦击Bean处理。例如AOP
  15. registerBeanPostProcessors(beanFactory);
  16. beanPostProcess.end();
  17. // Initialize message source for this context.
  18. initMessageSource();
  19. // 初始化广播器,用于发布事件
  20. initApplicationEventMulticaster();
  21. // 初始话context上下文特殊bean,例如tomcat容器
  22. onRefresh();
  23. // Check for listener beans and register them.
  24. registerListeners();
  25. // 实例化bean
  26. finishBeanFactoryInitialization(beanFactory);
  27. // Last step: publish corresponding event.
  28. finishRefresh();
  29. }
  30. }

            以ServletWebServerFactoryAutoConfiguration配置类为例,解释一下全局配置文件中的属性如何生效,比如:server.port=8081,是如何生效的(当然不配置也会有默认值,这个默认值来自于org.apache.catalina.startup.Tomcat)

在ServletWebServerFactoryAutoConfiguration类上,有一个@EnableConfigurationProperties注解:开启配置属性

server.port等,通过@ConfigurationProperties注解,绑定到对应的XxxxProperties配置实体类上封装为一个bean,然后再通过@EnableConfigurationProperties注解导入到Spring容器中。

Spring Boot启动的时候会通过@EnableAutoConfiguration注解找到META-INF/spring.factories配置文件中的所有自动配置类,并对其进行加载,而这些自动配置类都是以AutoConfiguration结尾来命名的,它实际上就是一个JavaConfig形式的Spring容器配置类,它能通过以Properties结尾命名的类中取得在全局配置文件中配置的属性如:server.port,而XxxxProperties类是通过@ConfigurationProperties注解与全局配置文件中对应的属性进行绑定的。

    2.1.2、启动内置tomcat

        refreshContext(..)-->AbstractApplicationContext#refresh -->onRefresh() -->ServletWebServerApplicationContext#onRefresh-->createWebServer()-->getWebServerFactory()-->factory.getWebServer(..) -->getTomcatWebServer()-->initialize

    1)、getWebServerFactory()

    默认springboot使用tomacat容器

    自动装配获取:spring-boot-autoconfigure的SPI文件中(这里注意spring boot2.7官方不推荐使用spring.factories了,EnableAutoConfiguration采用 META-INF/spring/%s.imports)

    通过Import导入EmbeddedTomcat、EmbeddedJetty、EmbeddedUndertow

  1. @AutoConfiguration
  2. @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
  3. @ConditionalOnClass(ServletRequest.class)
  4. @ConditionalOnWebApplication(type = Type.SERVLET)
  5. @EnableConfigurationProperties(ServerProperties.class)
  6. @Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
  7. ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
  8. ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
  9. ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
  10. public class ServletWebServerFactoryAutoConfiguration {

    分析EmbeddedTomcat,条件装配存在Tomcat类装配TomcatServletWebServerFactory

  1. @Configuration(proxyBeanMethods = false)
  2. @ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
  3. @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
  4. static class EmbeddedTomcat {
  5. @Bean
  6. TomcatServletWebServerFactory tomcatServletWebServerFactory(

    pom文件只要依赖spring-boot-start-tomacat会将Tomcat类引入到项目中,满足EmbeddedTomcat条件装配条件,向容器注入TomcatServletWebServerFactory,springboot容器启动getWebServerFactory会获取TomcatServletWebServerFactory创建Tomcat web容器

    2)、Tomacat实现类:new Tocmat并完成了一些初始化配置 --> getTomcatWebServer(创建webserver实例)并启动tomcat容器(this.tomcat.start())

  1. @Override
  2. public WebServer getWebServer(ServletContextInitializer... initializers) {
  3. if (this.disableMBeanRegistry) {
  4. Registry.disableRegistry();
  5. }
  6. Tomcat tomcat = new Tomcat();
  7. File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
  8. tomcat.setBaseDir(baseDir.getAbsolutePath());
  9. for (LifecycleListener listener : this.serverLifecycleListeners) {
  10. tomcat.getServer().addLifecycleListener(listener);
  11. }
  12. Connector connector = new Connector(this.protocol);
  13. connector.setThrowOnFailure(true);
  14. tomcat.getService().addConnector(connector);
  15. customizeConnector(connector);
  16. tomcat.setConnector(connector);
  17. tomcat.getHost().setAutoDeploy(false);
  18. configureEngine(tomcat.getEngine());
  19. for (Connector additionalConnector : this.additionalTomcatConnectors) {
  20. tomcat.getService().addConnector(additionalConnector);
  21. }
  22. prepareContext(tomcat.getHost(), initializers);
  23. return getTomcatWebServer(tomcat);
  24. }
    2.6、 afterRefresh
    
2.7、Banner打印类

    1)、默认SpringBootBanner

    printBanner(env)->bannerPrinter.print->SpringBootBanner#printBanner

  1. class SpringBootBanner implements Banner {
  2. private static final String[] BANNER = { "", " . ____ _ __ _ _",
  3. " /\\\\ / ___'_ __ _ _(_)_ __ __ _ \\ \\ \\ \\", "( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\",
  4. " \\\\/ ___)| |_)| | | | | || (_| | ) ) ) )", " ' |____| .__|_| |_|_| |_\\__, | / / / /",
  5. " =========|_|==============|___/=/_/_/_/" };
  6. private static final String SPRING_BOOT = " :: Spring Boot :: ";
  7. private static final int STRAP_LINE_SIZE = 42;
  8. @Override
  9. public void printBanner(Environment environment, Class<?> sourceClass, PrintStream printStream) {
  10. for (String line : BANNER) {
  11. printStream.println(line);
  12. }
  13. String version = SpringBootVersion.getVersion();
  14. version = (version != null) ? " (v" + version + ")" : "";
  15. StringBuilder padding = new StringBuilder();
  16. while (padding.length() < STRAP_LINE_SIZE - (version.length() + SPRING_BOOT.length())) {
  17. padding.append(" ");
  18. }
  19. printStream.println(AnsiOutput.toString(AnsiColor.GREEN, SPRING_BOOT, AnsiColor.DEFAULT, padding.toString(),
  20. AnsiStyle.FAINT, version));
  21. printStream.println();
  22. }
  23. }

     2)、自定义bannner打印

    在Resources目录下新增banner.txt文件,自定义打印banner效果

    2.8、Runners运行器

  1. private void callRunners(ApplicationContext context, ApplicationArguments args) {
  2. List<Object> runners = new ArrayList<>();
  3. runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
  4. runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
  5. AnnotationAwareOrderComparator.sort(runners);
  6. for (Object runner : new LinkedHashSet<>(runners)) {
  7. if (runner instanceof ApplicationRunner) {
  8. callRunner((ApplicationRunner) runner, args);
  9. }
  10. if (runner instanceof CommandLineRunner) {
  11. callRunner((CommandLineRunner) runner, args);
  12. }
  13. }
  14. }
  15. private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
  16. try {
  17. (runner).run(args);
  18. }
  19. catch (Exception ex) {
  20. throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
  21. }
  22. }
  23. private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
  24. try {
  25. (runner).run(args.getSourceArgs());
  26. }
  27. catch (Exception ex) {
  28. throw new IllegalStateException("Failed to execute CommandLineRunner", ex);
  29. }
  30. }

调用ApplicationRunner和CommandLineRunner类执行run方法(order相同ApplicationRunner优先级更高),一般需要在初始化完毕的时候执行,例如加载数据库的配置信息

    1)、自定义ApplicationRunner

  1. @Component
  2. public class MyApplicationRunner implements ApplicationRunner {
  3. @Override
  4. public void run(ApplicationArguments args) throws Exception {
  5. System.out.println("my application runner: init dbserver application");
  6. }
  7. }
3、Spring boot中的扩展机制
    1)、自定义初始化器,在refreh之前
    2)、事件监听器
    3)、Runner
    4)、自定义BeanFactoryPostProcessor用于修改beanFactory的属性值
    5)、bean的扩展 beanPostPrecessor拦截bean
    6)、aop扩展机制:前置 后置 环绕通知
    7)、Aware
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/618619
推荐阅读
相关标签
  

闽ICP备14008679号