前言

我们启动一个springboot项目,最简单的就是配置一个springboot启动类,然后运行即可

@SpringBootApplication
public class SpringBoot {
	public static void main(String[] args) {
		SpringApplication.run(SpringBoot.class, args);
	}
}

通过上面的代码,我们可以看出springboot启动的关键主要有两个地方,

  • 第一个就是@SpringBootApplication注解
  • 第二个就是 SpringApplication.run(SpringBoot.class, args);

SpringBoot启动流程图

图1:
在这里插入图片描述

图2:
在这里插入图片描述

一、@SpringBootApplication 注解解析

1.1 @SpringBootApplication

我们直接追踪@SpringBootApplication的源码,可以看到其实@SpringBootApplication是一个组合注解,他分别是由底下这些注解组成。

@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) })

这些注解虽然看起来很多,但是除去元注解,真正起作用的注解只有以下三个注解:

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan

那这三个注解是有啥用?其实在Spring Boot 1.2版之前,或者我们初学者刚开始接触springboot时,都还没开始使用@SpringBootApplication这个注解,而是使用以上三个注解启动项目。如果有兴趣的,也可以手动敲敲代码,就会发现这样也可以正常启动项目!

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
public class SpringBoot {
	public static void main(String[] args) {
		SpringApplication.run(SpringBoot.class, args);
	}
}

所以说这三个注解才是背后的大佬,@SpringBootApplication只是个空壳子。接下来,我来说明下这三个注解各自的作用。

1.2 @SpringBootConfiguration

同样,我们跟踪下@SpringBootConfiguration的源代码,看下他由哪些注解组成

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration

可以看到,除去元注解,剩下的@Configuration注解我相信大家应该都很熟了!我们springboot为什么可以去除xml配置,靠的就是@Configuration这个注解。所以,它的作用就是将当前类申明为配置类,同时还可以使用@bean注解将类以方法的形式实例化到spring容器,而方法名就是实例名,看下代码你就懂了!

@Configuration
public class TokenAutoConfiguration {
	@Bean
	public TokenService tokenService() {
		return new TokenService();
	}
}

作用等同于xml配置文件的

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:cache="http://www.springframework.org/schema/cache" xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 
	 					http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd 
	 					http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
	 					http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
	 					http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd ">
    <!--实例化bean-->
  <bean id="tokenService" class="TokenService"></bean>
</beans>

1.3 @ComponentScan

我们先说下@ComponentScan作用。他的作用就是扫描当前包以及子包,将有@Component,@Controller,@Service,@Repository等注解的类注册到容器中,以便调用。
注:大家第一眼见到@ComponentScan这个注解的时候是否有点眼熟?之前,一些传统框架用xml配置文件配置的时候,一般都会使用context:component-scan来扫描包。以下两中写法的效果是相同的`

@Configuration
@ComponentScan(basePackages="XXX")
public class SpringBoot {

}


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:cache="http://www.springframework.org/schema/cache" xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 
	 					http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd 
	 					http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
	 					http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
	 					http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd ">

	<!-- 扫描需要被调用的注解文件包 -->
	<context:component-scan base-package="XXX"></context:component-scan>
</beans>

注:如果@ComponentScan不指定basePackages,那么默认扫描当前包以及其子包,而@SpringBootApplication里的@ComponentScan就是默认扫描,所以我们一般都是把springboot启动类放在最外层,以便扫描所有的类。

1.4 @EnableAutoConfiguration

这里先总结下@EnableAutoConfiguration的工作原理,大家后面看的应该会更清晰:
它主要就是通过内部的方法,扫描classpath的META-INF/spring.factories配置文件(key-value),将其中的
org.springframework.boot.autoconfigure.EnableAutoConfiguration 对应的配置项实例化并且注册到spring容器。

ok,我们同样打开@EnableAutoConfiguration源码,可以发现他是由以下几个注解组成的

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)

除去元注解,主要注解就是@AutoConfigurationPackage和@Import(AutoConfigurationImportSelector.class)
我们springboot项目为什么可以自动载入应用程序所需的bean?就是因为这个神奇的注解@Import。那么这个@Import怎么这么牛皮?没关系!我们一步一步的看下去!
首先我们先进入AutoConfigurationImportSelector类,可以看到他有一个方法selectImports()
在这里插入图片描述
继续跟踪,进入getAutoConfigurationEntry()方法,可以看到这里有个List集合,那这个List集合又是干嘛的?没事,我们继续跟踪getCandidateConfigurations()方法!
在这里插入图片描述
可以看到这里有个方法,这个方法的作用就是读取classpath下的META-INF/spring.factories文件的配置,将key为 org.springframework.boot.autoconfigure.EnableAutoConfiguration 对应的配置项读取出来,通过反射机制实例化为配置文件,然后注入spring容器。

注:假如你想要实例化一堆bean,可以通过配置文件先将这些bean实例化到容器,等其他项目调用时,在spring.factories中写入这个配置文件的路径即可!

然后直接在SpringFactoriesLoader.loadFactoryNames;这个方法后面打个断点,可以在返回的集合里找到我们自定义的配置文件路径!
在这里插入图片描述

说明成功引入我们自定义的依赖包!

二、SpringApplication.run()原理解析

SpringApplication.run()原理相对于前面注解的原理,会稍微麻烦点,为了方便我会适当贴出一些注解代码。
首先我们点击查看run方法的源码

在这里插入图片描述
可以看出,其实SpringApplication.run()包括两个部分,一部分就是创建SpringApplicaiton实例,另一部分就是调用run()方法,那他们又是怎么运行的?

2.1 SpringApplicaiton创建

继续跟踪SpringApplication实例的源码
在这里插入图片描述
继续跟踪进入,到如下这个方法中

@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
	this.resourceLoader = resourceLoader;
	Assert.notNull(primarySources, "PrimarySources must not be null");
	this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
	//获取应用类型
	this.webApplicationType = WebApplicationType.deduceFromClasspath();
	//获取所有初始化器
	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
	//获取所有监听器
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
	//定位main方法
	this.mainApplicationClass = deduceMainApplicationClass();
}

2.1.1 获取应用类型

跟踪deduceFromClasspath方法
在这里插入图片描述
从返回结果我们可以看出应用类型一共有三种,分别是

  • NONE: 非web应用,即不会启动服务器
  • SERVLET: 基于servlet的web应用
  • REACTIVE: 响应式web应用(暂未接触过)

判断一共涉及四个常量:
WEBFLUX_INDICATOR_CLASS , WEBMVC_INDICATOR_CLASS,JERSEY_INDICATOR_CLASS,SERVLET_INDICATOR_CLASSES

springboot在初始化容器的时候,会对以上四个常量所对应的class进行判断,看看他们是否存在,从而返回应用类型!至于常量代表哪些class,大家可以自己跟踪看看,也在当前类中

2.1.2 获取初始化器

跟踪进入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();
		// Use names and ensure unique to protect against duplicates
		//获取所有初始化器的名称集合
		Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		//根据名称集合实例化这些初始化器
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
		//排序		
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

从代码可以看出是在META-INF/spring.factories配置文件里获取初始化器,然后实例化、排序后再设置到initializers属性中

2.1.3 获取初监听器

其实监听器和初始化的操作是基本一样的

2.1.4 定位main方法

跟踪源码进入deduceMainApplicationClass方法

private Class<?> deduceMainApplicationClass() {
		try {
		    //通过创建运行时异常的方式获取栈
			StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
			//遍历获取main方法所在的类并且返回
			for (StackTraceElement stackTraceElement : stackTrace) {
				if ("main".equals(stackTraceElement.getMethodName())) {
					return Class.forName(stackTraceElement.getClassName());
				}
			}
		}
		catch (ClassNotFoundException ex) {
			// Swallow and continue
		}
		return null;
	}

2.2 SpringApplication.run()调用

2.2.1 Run代码总览
public ConfigurableApplicationContext run(String... args) {
    //1、创建并启动计时监控类
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    //2、初始化应用上下文和异常报告集合
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    //3、设置系统属性“java.awt.headless”的值,默认为true,用于运行headless服务器,进行简单的图像处理,多用于在缺少显示屏、键盘或者鼠标时的系统配置,很多监控工具如jconsole 需要将该值设置为true
    configureHeadlessProperty();
    //4、创建所有spring运行监听器并发布应用启动事件,简单说的话就是获取SpringApplicationRunListener类型的实例(EventPublishingRunListener对象),并封装进SpringApplicationRunListeners对象,然后返回这个SpringApplicationRunListeners对象。说的再简单点,getRunListeners就是准备好了运行时监听器EventPublishingRunListener。
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting();
    try {
        //5、初始化默认应用参数类
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        //6、根据运行监听器和应用参数来准备spring环境
        ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
        //将要忽略的bean的参数打开
        configureIgnoreBeanInfo(environment);
        //7、创建banner打印类
        Banner printedBanner = printBanner(environment);
        //8、创建应用上下文,可以理解为创建一个容器
        context = createApplicationContext();
        //9、准备异常报告器,用来支持报告关于启动的错误
        exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
        //10、准备应用上下文,该步骤包含一个非常关键的操作,将启动类注入容器,为后续开启自动化提供基础
        prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        //11、刷新应用上下文
        refreshContext(context);
        //12、应用上下文刷新后置处理,做一些扩展功能
        afterRefresh(context, applicationArguments);
        //13、停止计时监控类
        stopWatch.stop();
        //14、输出日志记录执行主类名、时间信息
        if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
        }
        //15、发布应用上下文启动监听事件
        listeners.started(context);
        //16、执行所有的Runner运行器
        callRunners(context, applicationArguments);
    }catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, listeners);
        throw new IllegalStateException(ex);
    }
    try {
        //17、发布应用上下文就绪事件
        listeners.running(context);
    }catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, null);
        throw new IllegalStateException(ex);
    }
    //18、返回应用上下文
    return context;
}
2.2.2 创建spring运行监听器并发布应用启动事件
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();

//创建spring监听器
private SpringApplicationRunListeners getRunListeners(String[] args) {
    Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
    return new SpringApplicationRunListeners(logger,
                getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}

SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
    this.log = log;
    this.listeners = new ArrayList<>(listeners);
}

//循环遍历获取监听器
void starting() {
    for (SpringApplicationRunListener listener : this.listeners) {
        listener.starting();
    }
}

//此处的监听器可以看出是事件发布监听器,主要用来发布启动事件
@Override
public void starting() {
    //这里是创建application事件‘applicationStartingEvent’
    this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}

//applicationStartingEvent是springboot框架最早执行的监听器,在该监听器执行started方法时,会继续发布事件,主要是基于spring的事件机制
    @Override
    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        //获取线程池,如果为空则同步处理。这里线程池为空,还未初始化
        Executor executor = getTaskExecutor();
        for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            if (executor != null) {
                //异步发送事件
                executor.execute(() -> invokeListener(listener, event));
            }
            else {
                //同步发送事件
                invokeListener(listener, event);
            }
        }
    }

SpringApplicationRunListener这个接口是干啥的呢?没错,他就是用来加载我们配置文件用的。接下来我弄个简单的例子,大家就知道怎么用了。

2.2.2 番外(listener示例,可跳过)

主要实现自定义监听器并且读取我们配置文件内容,先献上我的文件结构
在这里插入图片描述

创建一个maven项目,pom配置只需要添加web依赖即可

<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.8.RELEASE</version>
  </parent>
  <dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
	</dependencies>
  <build>

在resource自定义配置文件my.properties

tzr.name=zzk

自定义监听器,这里主要是对starting、environmentPrepared、started、running方法进行实现

package zzk;

import java.io.IOException;
import java.util.Properties;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
/**
 * 集成监听器加载我们的配置文件
 * @author zhanzhk
 *
 */
public class MyListener implements SpringApplicationRunListener,Ordered {

	private SpringApplication application;
	private String[] args;
	
	
	@Override
	public void starting() {
		System.out.println("表示准备开始使用监听器");

	}

	public MyListener(SpringApplication application, String[] args) {
		this.application = application;
		this.args = args;
	}
	
	@Override
	public void environmentPrepared(ConfigurableEnvironment environment) {
		System.out.println("表示已经开始读取配置文件");
		//配置文件到程序,再然后放入springboot容器
		Properties properties=new Properties();
		try {
			//读取properties容器
			properties.load(this.getClass().getClassLoader().getResourceAsStream("my.properties"));
			//读取名字为my
			PropertySource propertySource=new PropertiesPropertySource("my",properties) ;
			//加载资源到springboot容器
			MutablePropertySources propertySources=environment.getPropertySources();
			propertySources.addLast(propertySource);
			//换种思路,如果你配置文件是放在网络上,可以直接读取放入我们的项目中
		
		} catch (IOException e) {
			System.out.println("出错");
		}

	}

	@Override
	public void contextPrepared(ConfigurableApplicationContext context) {
		// TODO Auto-generated method stub

	}

	@Override
	public void contextLoaded(ConfigurableApplicationContext context) {
		// TODO Auto-generated method stub

	}

	@Override
	public void started(ConfigurableApplicationContext context) {
		System.out.println("表示初始化容器已经结束");

	}

	@Override
	public void running(ConfigurableApplicationContext context) {
		System.out.println("表示可以使用springboot了");
	}

	@Override
	public void failed(ConfigurableApplicationContext context, Throwable exception) {
		// TODO Auto-generated method stub

	}

	//读取优先级
	@Override
	public int getOrder() {
		// TODO Auto-generated method stub
		return -1;
	}

}


然后编写controller文件对我们的配置参数进行调用

package zzk.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class Application {

	@Value("${tzr.name}")
	private String name;

	@RequestMapping("test")
	@ResponseBody
	public String test() {
		String x = name;
		return x;
	}
}


ok,那我们自定义的监听器springboot程序又是如何获取的?前面我们代码里讲过了,它主要是读取META-INF底下的spring.factories文件,然后获取监听器,ok那就简单了,我们直接照着EventPublishingRunListener一样在resource增加METAA_INF/spring.factories文件

org.springframework.boot.SpringApplicationRunListener=\
zzk.MyListener

最后设置spring启动器

package zzk;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Springboot {
	public static void main(String[] args) {
		SpringApplication.run(Springboot.class, args);
	}
}


启动!可以看到启动信息
在这里插入图片描述

然后我们再调用controller方法
在这里插入图片描述成功读取我们自定义的配置文件,现在再回头看看run方法,是不是就清晰了!

2.2.3 准备基础运行环境

初始化默认应用参数类

ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
public DefaultApplicationArguments(String... args) {
    Assert.notNull(args, "Args must not be null");
    this.source = new Source(args);
    this.args = args;
}

根据运行监听器和应用参数来准备spring环境

ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
//详细环境的准备
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
    ApplicationArguments applicationArguments) {
    // 获取或者创建应用环境
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    // 配置应用环境,配置propertySource和activeProfiles
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    //listeners环境准备,广播ApplicationEnvironmentPreparedEvent
    ConfigurationPropertySources.attach(environment);
    listeners.environmentPrepared(environment);
    //将环境绑定给当前应用程序
    bindToSpringApplication(environment);
    //对当前的环境类型进行判断,如果不一致进行转换
    if (!this.isCustomEnvironment) {
        environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
                    deduceEnvironmentClass());
    }
    //配置propertySource对它自己的递归依赖
    ConfigurationPropertySources.attach(environment);
    return environment;
}
// 获取或者创建应用环境,根据应用程序的类型可以分为servlet环境、标准环境(特殊的非web环境)和响应式环境
private ConfigurableEnvironment getOrCreateEnvironment() {
    //存在则直接返回
        if (this.environment != null) {
            return this.environment;
        }
    //根据webApplicationType创建对应的Environment
        switch (this.webApplicationType) {
        case SERVLET:
            return new StandardServletEnvironment();
        case REACTIVE:
            return new StandardReactiveWebEnvironment();
        default:
            return new StandardEnvironment();
        }
    }
//配置应用环境
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
    if (this.addConversionService) {
        ConversionService conversionService = ApplicationConversionService.getSharedInstance();
        environment.setConversionService((ConfigurableConversionService) conversionService);
    }
    //配置property sources
    configurePropertySources(environment, args);
    //配置profiles
    configureProfiles(environment, args);
}

创建banner的打印类

Banner printedBanner = printBanner(environment);//打印类的详细操作过程private Banner printBanner(ConfigurableEnvironment environment) {       if (this.bannerMode == Banner.Mode.OFF) {           return null;        }       ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader             : new DefaultResourceLoader(getClassLoader());      SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);     if (this.bannerMode == Mode.LOG) {          return bannerPrinter.print(environment, this.mainApplicationClass, logger);     }       return bannerPrinter.print(environment, this.mainApplicationClass, System.out); }

创建应用的上下文:根据不同哦那个的应用类型初始化不同的上下文应用类

context = createApplicationContext();

protected ConfigurableApplicationContext createApplicationContext() {
		return this.applicationContextFactory.create(this.webApplicationType);
	}

protected ConfigurableApplicationContext createApplicationContext() {      
	Class<?> contextClass = this.applicationContextClass;       
	if (contextClass == null) {         
		try {               
			switch (this.webApplicationType) {
			case SERVLET: contextClass = Class.forName(DEFAULT_SERVLET_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);   
}

2.2.4 准备上下文
prepareContext(context, environment, listeners, applicationArguments, printedBanner);

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,           SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {   
	
	//应用上下文的environment     
	context.setEnvironment(environment);        
	
	//应用上下文后处理      
	postProcessApplicationContext(context);     
	
	//为上下文应用所有初始化器,执行容器中的
	applicationContextInitializer(spring.factories的实例)//将所有的初始化对象放置到context对象中      
	applyInitializers(context);
	
	//触发所有SpringApplicationRunListener监听器的ContextPrepared事件方法。添加所有的事件监听器
	listeners.contextPrepared(context);
	
	//记录启动日志        
	if (this.logStartupInfo) {
		logStartupInfo(context.getParent() == null);            
		logStartupProfileInfo(context);     
	}       
	
	// 注册启动参数bean,将容器指定的参数封装成bean,注入容器      
	ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
	beanFactory.registerSingleton("springApplicationArguments", applicationArguments);      
	
	//设置banner      
	if (printedBanner != null) {            
		beanFactory.registerSingleton("springBootBanner", printedBanner);       
		}
		
	if (beanFactory instanceof DefaultListableBeanFactory) {            
	((DefaultListableBeanFactory) beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);      
	}       
	
	if (this.lazyInitialization) {          
	context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());      
	}       
	
	// 加载所有资源,指的是启动器指定的参数       
	Set<Object> sources = getAllSources();      
	Assert.notEmpty(sources, "Sources must not be empty");      
	
	//将bean加载到上下文中      
	load(context, sources.toArray(new Object[0]));      
	
	//触发所有springapplicationRunListener监听器的contextLoaded事件方法,        
	listeners.contextLoaded(context);   
}
	
//这里没有做任何的处理过程,因为beanNameGenerator和resourceLoader默认为空,可以方便后续做扩展处理    
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {     
	if (this.beanNameGenerator != null) {   
		context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,  
		this.beanNameGenerator);        
	}       
	
	if (this.resourceLoader != null) {          
		if (context instanceof GenericApplicationContext) {
			((GenericApplicationContext) context).setResourceLoader(this.resourceLoader); 
		}

		if (context instanceof DefaultResourceLoader) {
			((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());         
		}      
	}       
	
	if (this.addConversionService) {  
	context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance()); 
	}   
}

//将启动器类加载到spring容器中,为后续的自动化配置奠定基础,之前看到的很多注解也与此相关    
protected void load(ApplicationContext context, Object[] sources) {
	if (logger.isDebugEnabled()) {          
		logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(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();  
}

//springboot会优先选择groovy加载方式,找不到在选择java方式    
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)) {          
		this.annotatedReader.register(source);          
		return 1;       
	}       
	
	return 0;   
}
2.2.5 刷新上下文

springboot的启动分为两部分,一部分是注解,一部分是SpringApplication.run(Springboot.class, args),那么我们的注解又是如何嵌入到程序中呢?靠的就是refreshContext方法,同理,我们跟踪源码进入refreshContext方法

在这里插入图片描述
在这里插入图片描述

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			//  准备这个上下文来刷新。
			prepareRefresh();

			// 告诉子类刷新内部bean工厂。
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			//  准备bean在此上下文中使用。
			prepareBeanFactory(beanFactory);

			try {
				//  允许在上下文子类中对bean工厂进行后处理。
				postProcessBeanFactory(beanFactory);

				//  调用在上下文中注册为bean的工厂处理器。
				invokeBeanFactoryPostProcessors(beanFactory);

				//  注册拦截bean创建的bean处理器。
				registerBeanPostProcessors(beanFactory);

				//  初始化此上下文的消息源。
				initMessageSource();

				//  为此上下文初始化事件多播。
				initApplicationEventMulticaster();

				//  在特定的上下文子类中初始化其他特殊bean。
				onRefresh();

				//  检查侦听器bean并注册它们。
				registerListeners();

				//  实例化所有剩余的(非拉齐-init)单例。
				finishBeanFactoryInitialization(beanFactory);

				//  最后一步:发布相应事件.
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				//  销毁已经创建的单例以避免悬空资源。
				destroyBeans();

				//  重置“actiove”标志。
				cancelRefresh(ex);

				// 向调用者传播异常。
				throw ex;
			}

			finally {
				//  重置Spring核心中常见的内省缓存,因为我们可能不再需要单例bean的元数据了。。。
				resetCommonCaches();
			}
		}
	}

到这里,就可以看到一系列bean的操作,继续跟踪进入invokeBeanFactoryPostProcessors(调用在上下文中注册为bean的工厂处理器)方法
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
进入ConfigurationClassParser这个类后,方法调用也是挺绕的,这里就不深究了…进入这个类主要是想看下它的一些方法,因为对于springboot注解的引用就是在这个类进行的,比如doProcessConfigurationClass:

    @Nullable
	protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
			throws IOException {

		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			// Recursively process any member (nested) classes first
			processMemberClasses(configClass, sourceClass);
		}

		//处理 @PropertySource 注解
		for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), PropertySources.class,
				org.springframework.context.annotation.PropertySource.class)) {
			if (this.environment instanceof ConfigurableEnvironment) {
				processPropertySource(propertySource);
			}
			else {
				logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
						"]. Reason: Environment must implement ConfigurableEnvironment");
			}
		}

		// 处理 @ComponentScan 注解
		Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
		if (!componentScans.isEmpty() &&
				!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
			for (AnnotationAttributes componentScan : componentScans) {
				// The config class is annotated with @ComponentScan -> perform the scan immediately
				Set<BeanDefinitionHolder> scannedBeanDefinitions =
						this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
				// Check the set of scanned definitions for any further config classes and parse recursively if needed
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
					if (bdCand == null) {
						bdCand = holder.getBeanDefinition();
					}
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}

		 
		 //处理 @Import 注解
		processImports(configClass, sourceClass, getImports(sourceClass), true);

		
		//处理 @ImportResource 注解
		AnnotationAttributes importResource =
				AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
		if (importResource != null) {
			String[] resources = importResource.getStringArray("locations");
			Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
			for (String resource : resources) {
				String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
				configClass.addImportedResource(resolvedResource, readerClass);
			}
		}

		//处理 @Bean 注解
		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

		// Process default methods on interfaces
		processInterfaces(configClass, sourceClass);

		// Process superclass, if any
		if (sourceClass.getMetadata().hasSuperClass()) {
			String superclass = sourceClass.getMetadata().getSuperClassName();
			if (superclass != null && !superclass.startsWith("java") &&
					!this.knownSuperclasses.containsKey(superclass)) {
				this.knownSuperclasses.put(superclass, configClass);
				// Superclass found, return its annotation metadata and recurse
				return sourceClass.getSuperClass();
			}
		}

		// No superclass -> processing is complete
		return null;
	}

2.2.6 刷新上下文后置处理
afterRefresh(context, applicationArguments);

protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
	}
2.2.7 上下文准备后其他处理

停止计时监控类:计时监听器停止,并统计一些任务执行信息

stopWatch.stop();

public void stop() throws IllegalStateException {      
	if (this.currentTaskName == null) {         
		throw new IllegalStateException("Can't stop StopWatch: it's not running");      
	}       
	
	long lastTime = System.nanoTime() - this.startTimeNanos;        
	this.totalTimeNanos += lastTime;        
	this.lastTaskInfo = new TaskInfo(this.currentTaskName, lastTime);       
	if (this.keepTaskList) {            
		this.taskList.add(this.lastTaskInfo);       
	}       
	++this.taskCount;       
	this.currentTaskName = null;    
}

输出日志记录执行主类名、时间信息

if (this.logStartupInfo) {  
	new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}

发布应用上下文启动完成事件:触发所有SpringapplicationRunListener监听器的started事件方法

listeners.started(context); 

void started(ConfigurableApplicationContext context) {      
	for (SpringApplicationRunListener listener : this.listeners) {          
		listener.started(context);      
	}   
}

执行所有Runner执行器:执行所有applicationRunner和CommandLineRunner两种运行器

callRunners(context, applicationArguments);

private void callRunners(ApplicationContext context, ApplicationArguments args) {   
     List<Object> runners = new ArrayList<>();       
	 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);           
		}       
	}   
}

发布应用上下文就绪事件:触发所有springapplicationRunnListener的running事件方法

listeners.running(context);

void running(ConfigurableApplicationContext context) {       
for (SpringApplicationRunListener listener : this.listeners) {          
	listener.running(context);      
	}   
}

返回上下文

return content;

2.3 内置Tomcat

其实,内置tomcat应该要归在refreshContext讲的,因为tomcat就是在注解引入的类中生成的,而refreshContext可以引入注解。不过为了更清楚,这里分开吧。前面说了,我们refreshContext是刷新上下文,那如果想要知道上下文中是否存在生成tomcat的类,我们直接去最后返回的上下文中找对应的类即可!

ok,我们在main方法写获取上下文的代码,并且打印出对应的name

package zzk;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class Springboot {
	public static void main(String[] args) {
		ConfigurableApplicationContext configurableApplicationContext = SpringApplication.run(Springboot.class, args);
		String[] xs = configurableApplicationContext.getBeanDefinitionNames();
		for (String x : xs) {
			System.out.println(x);
		}

	}
}


直接启动,可以看到有org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration这个类
在这里插入图片描述
ok,我们点开这个类,跟踪源码
在这里插入图片描述
我们知道,springboot其实有三种内容服务器,分别是Tomcat,Jetty,Undertow。默认内置tomcat,。我们继续跟踪EmbeddedTomcat.class
在这里插入图片描述
在这里插入图片描述
可以看到,其实这里的tomcat服务器是内部通过java代码实现的。到这里,run()方法就算结束了。如果后续想深入了解的可以自己看看源码。其实,run()方法总结起来并不多,大方向无非是配置环境参数,引入注解刷新上下文。其他的一些捕获异常、计时操作都是非重点操作

总结

springboot原理:包装spring核心注解,使用springmvc无xml进行启动,通过自定义starter和maven依赖简化开发代码,开发者能够快速整合第三方框架,通过java语言内嵌入tomcat

springboot启动流程

--------------------------------创建springbootApplication对象---------------------------------------------
1. 创建springbootApplication对象springboot容器初始化操作
2. 获取当前应用的启动类型。
	注1:通过判断当前classpath是否加载servlet类,返回servlet web启动方式。
	注2:webApplicationType三种类型:
		1.reactive:响应式启动(spring5新特性)
		2.none:即不嵌入web容器启动(springboot放在外部服务器运行 )
		3.servlet:基于web容器进行启动
3. 读取springboot下的META-INFO/spring.factories文件,获取对应的ApplicationContextInitializer装配到集合
4. 读取springboot下的META-INFO/spring.factories文件,获取对应的ApplicationListener装配到集合
5. mainApplicationClass,获取当前运行的主函数
6. 
7. 
------------------调用springbootApplication对象的run方法,实现启动,返回当前容器的上下文----------------------------------------------
8. 调用run方法启动
9. StopWatch stopWatch = new StopWatch(),记录项目启动时间
10. getRunListeners,读取META-INF/spring.factores,将SpringApplicationRunListeners类型存到集合中
11. listeners.starting();循环调用starting方法
12. prepareEnvironment(listeners, applicationArguments);将配置文件读取到容器中
		读取多数据源:classpath:/,classpath:/config/,file:./,file:./config/底下。其中classpath是读取编译后的,file是读取编译前的
		支持yml,yaml,xml,properties
13. Banner printedBanner = printBanner(environment);开始打印banner图,就是sprongboot启动最开头的图案
14. 初始化AnnotationConfigServletWebServerApplicationContext对象
15. 刷新上下文,调用注解,refreshContext(context);
16. 创建tomcat
17. 加载springmvc
18. 刷新后的方法,空方法,给用户自定义重写afterRefresh()
19. stopWatch.stop();结束计时
20. 使用广播和回调机制告诉监听者springboot容器已经启动化成功,listeners.started(context);
21. 使用广播和回调机制告诉监听者springboot容器已经启动化成功,listeners.started(context);
22. 返回上下文

SpringBoot获取factory文件的方式

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();
        // Use names and ensure unique to protect against duplicates
        Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
}
-----------------------------
    public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
        String factoryTypeName = factoryType.getName();
        return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
    }

    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = cache.get(classLoader);
        if (result != null) {
            return result;
        }

        try {
            Enumeration<URL> urls = (classLoader != null ?
                    classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                    ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
            result = new LinkedMultiValueMap<>();
            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                UrlResource resource = new UrlResource(url);
                Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                for (Map.Entry<?, ?> entry : properties.entrySet()) {
                    String factoryTypeName = ((String) entry.getKey()).trim();
                    for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
                        result.add(factoryTypeName, factoryImplementationName.trim());
                    }
                }
            }
            cache.put(classLoader, result);
            return result;
        }
        catch (IOException ex) {
            throw new IllegalArgumentException("Unable to load factories from location [" +
                    FACTORIES_RESOURCE_LOCATION + "]", ex);
        }
    }
-------------------------
    private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
            ClassLoader classLoader, Object[] args, Set<String> names) {
        List<T> instances = new ArrayList<>(names.size());
        for (String name : names) {
            try {
                //装载class文件到内存
                Class<?> instanceClass = ClassUtils.forName(name, classLoader);
                Assert.isAssignable(type, instanceClass);
                Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
                //通过反射创建实例
                T instance = (T) BeanUtils.instantiateClass(constructor, args);
                instances.add(instance);
            }
            catch (Throwable ex) {
                throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
            }
        }
        return instances;
    }

spring.factory文件中的类的作用

# PropertySource Loaders 属性文件加载器
org.springframework.boot.env.PropertySourceLoader=\
# properties文件加载器
org.springframework.boot.env.PropertiesPropertySourceLoader,\
# yaml文件加载器
org.springframework.boot.env.YamlPropertySourceLoader

# Run Listeners 运行时的监听器
org.springframework.boot.SpringApplicationRunListener=\
# 程序运行过程中所有监听通知都是通过此类来进行回调
org.springframework.boot.context.event.EventPublishingRunListener

# Error Reporters   错误报告器
org.springframework.boot.SpringBootExceptionReporter=\
org.springframework.boot.diagnostics.FailureAnalyzers

# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
# 报告spring容器的一些常见的错误配置
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
# 设置spring应用上下文的ID
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
# 使用环境属性context.initializer.classes指定初始化器进行初始化规则
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
# 将内置servlet容器实际使用的监听端口写入到environment环境属性中
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer

# Application Listeners
org.springframework.context.ApplicationListener=\
# 应用上下文加载完成后对缓存做清除工作,响应事件ContextRefreshEvent
org.springframework.boot.ClearCachesApplicationListener,\
# 监听双亲应用上下文的关闭事件并往自己的孩子应用上下文中传播,相关事件ParentContextAvailableEvent/ContextClosedEvent
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
# 如果系统文件编码和环境变量中指定的不同则终止应用启动。具体的方法是比较系统属性file.encoding和环境变量spring.mandatory-file-encoding是否相等(大小写不敏感)。
org.springframework.boot.context.FileEncodingApplicationListener,\
# 根据spring.output.ansi.enabled参数配置AnsiOutput
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
# EnvironmentPostProcessor,从常见的那些约定的位置读取配置文件,比如从以下目录读取#application.properties,application.yml等配置文件:
# classpath:
# file:.
# classpath:config
# file:./config/:
# 也可以配置成从其他指定的位置读取配置文件
org.springframework.boot.context.config.ConfigFileApplicationListener,\
# 监听到事件后转发给环境变量context.listener.classes指定的那些事件监听器
org.springframework.boot.context.config.DelegatingApplicationListener,\
# 一个SmartApplicationListener,对环境就绪事件ApplicationEnvironmentPreparedEvent/应用失败事件ApplicationFailedEvent做出响应,往日志DEBUG级别输出TCCL(thread context class loader)的classpath。
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
# 检测正在使用的日志系统,默认时logback,,此时日志系统还没有初始化
org.springframework.boot.context.logging.LoggingApplicationListener,\
# 使用一个可以和Spring Boot可执行jar包配合工作的版本替换liquibase ServiceLocator
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\
org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor,\
org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor

# Failure Analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanDefinitionOverrideFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoSuchMethodFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer

# FailureAnalysisReporters
org.springframework.boot.diagnostics.FailureAnalysisReporter=\
org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

# Application Listeners
org.springframework.context.ApplicationListener=\
# 另外单独启动一个线程实例化并调用run方法,包括验证器、消息转换器等
org.springframework.boot.autoconfigure.BackgroundPreinitializer

# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener

# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudServiceConnectorsAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveRestClientAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.rest.RestClientAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\
org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketRequesterAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketStrategiesAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.rsocket.RSocketSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration,\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,\
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,\
org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration

# Failure analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\
org.springframework.boot.autoconfigure.flyway.FlywayMigrationScriptMissingFailureAnalyzer,\
org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\
org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,\
org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer

# Template availability providers
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.web.servlet.JspTemplateAvailabilityProvider

其他

参考:https://blog.csdn.net/weixin_40496191/article/details/109098491
https://www.jianshu.com/p/cb6f923af609

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐