1.1、总体梳理
@SpringBootApplication
public class SampleTestApplication {
public static void main(String[] args) {
SpringApplication.run(SampleTestApplication.class, args);
}
}
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
// 这里分为两步,创建SpringApplication和run方法,primarySources就是主启动类
return new SpringApplication(primarySources).run(args);
}
1.2、创建SpringApplication
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 默认是null
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
// 记录主启动类
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 判断当前应用环境,后续就是根据这创建Spring的IOC容器
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 设置初始化器
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 设置监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 确定主配置类
this.mainApplicationClass = deduceMainApplicationClass();
}
static WebApplicationType deduceFromClasspath() {
// 从classpath下判断当前SpringBoot应用应该使用哪种环境启动
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
// 默认返回这个
return WebApplicationType.SERVLET;
}
/**
* 源码很简单,从deduceMainApplicationClass方法开始往上爬,哪一层调用栈上有main方法,方法对应的类就是主配置类,就返回这个类
*/
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
}
catch (ClassNotFoundException ex) {
// Swallow and continue
}
return null;
}
1.3、run方法
public ConfigurableApplicationContext run(String... args) {
// 创建StopWatch对象,仅用于验证性能. 也就是说,这个组件是用来监控启动时间的
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 创建空的IOC容器
ConfigurableApplicationContext context = null;
// 创建一组空的异常报告器
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
// 设置awt相关,设置应用在启动时,即使没有检测到显示器也允许其继续启动.服务器嘛,没显示器照样得运行
configureHeadlessProperty();
// 通过SpringFactoriesLoader.loadFactoryNames获取SpringApplicationRunListener,第2节已经分析过了
SpringApplicationRunListeners listeners = getRunListeners(args);
// 监听器回调,首次启动run方法时立即调用. 可用于非常早期的初始化(准备运行时环境之前)
listeners.starting();
try {
// 将运行参数args封装一下
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 环境准备
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
// 打印Banner
Banner printedBanner = printBanner(environment);
// 创建IOC容器
context = createApplicationContext();
// 默认返回的是FailureAnalyzers
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 初始化IOC容器
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 刷新容器,beanFactory的预处理,这边就是核心流程,加载创建容器中的bean,后面会单独分析
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
listeners.started(context);
// 调用启动加载器
callRunners(context, applicationArguments);
} catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
} catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
1.3.1、prepareEnvironment
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
// 创建运行时环境
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 配置运行时环境
configureEnvironment(environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach(environment);
// 监听器回调,SpringApplicationRunListener的environmentPrepared方法(Environment构建完成,但在创建ApplicationContext之前)
listeners.environmentPrepared(environment);
// 环境与应用绑定
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.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) {
// 默认是true
if (this.addConversionService) {
// 向容器中添加一个类型转换器,而且是共享的,线程安全的.实际上就是它在SpringWebMvc中做参数类型转换
ConversionService conversionService = ApplicationConversionService.getSharedInstance();
environment.setConversionService((ConfigurableConversionService) conversionService);
}
configurePropertySources(environment, args);
configureProfiles(environment, args);
}
1.3.2、打印banner
// 打印Banner
Banner printedBanner = printBanner(environment);
private Banner printBanner(ConfigurableEnvironment environment) {
// banner打印模式,默认是控制台打印
if (this.bannerMode == Banner.Mode.OFF) {
return null;
}
// this.resourceLoader默认为null,这边创建一个,用于加载资源
// ResourceLoader用于加载资源的策略接口(例如从类路径或文件系统资源)
ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader :
new DefaultResourceLoader(getClassLoader());
// 使用BannerPrinter打印Banner,this.banner默认也是null
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);
}
public Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {
// 获取Banner
Banner banner = getBanner(environment);
// 打印Banner
banner.printBanner(environment, sourceClass, out);
// 最后把Banner封装成PrintedBanner返回
return new PrintedBanner(banner, sourceClass);
}
private Banner getBanner(Environment environment) {
Banners banners = new Banners();
// 先加载图片Banner和文字Banner
banners.addIfNotNull(getImageBanner(environment));
banners.addIfNotNull(getTextBanner(environment));
// 只要有一个就返回
if (banners.hasAtLeastOneBanner()) {
return banners;
}
if (this.fallbackBanner != null) {
return this.fallbackBanner;
}
// 默认实现是SpringBootBanner
return DEFAULT_BANNER;
}
class SpringBootBanner implements Banner {
private static final String\[\] BANNER = { "", " . ____ _ __ _ _",
" /\\\\\\ / ___'_ __ _ _(_)_ __ __ _ \\\ \\\ \\\ \\\", "( ( )\\\___ | '_ | '_| | '_ \\\/ _` | \\\ \\\ \\\ \\\",
" \\\\\\/ ___)| |_)| | | | | || (_| | ) ) ) )", " ' |____| .__|_| |_|_| |_\\\__, | / / / /",
" =========|_|==============|___/=/_/_/_/" };
private static final String SPRING_BOOT = " :: Spring Boot :: ";
private static final int STRAP\_LINE\_SIZE = 42;
@Override
public void printBanner(Environment environment, Class<?> sourceClass, PrintStream printStream) {
for (String line : BANNER) {
printStream.println(line);
}
String version = SpringBootVersion.getVersion();
version = (version != null) ? " (v" \+ version + ")" : "";
StringBuilder padding = new StringBuilder();
while (padding.length() < STRAP\_LINE\_SIZE \- (version.length() + SPRING_BOOT.length())) {
padding.append(" ");
}
printStream.println(AnsiOutput.toString(AnsiColor.GREEN, SPRING_BOOT, AnsiColor.DEFAULT, padding.toString(),
AnsiStyle.FAINT, version));
printStream.println();
}
}
// 可以指定文字banner的位置
static final String BANNER_LOCATION_PROPERTY = "spring.banner.location";
// 可以指定图片banner的位置
static final String BANNER_IMAGE_LOCATION_PROPERTY = "spring.banner.image.location";
// 在resources目录下新建banner.txt文件,里面可以指定banner的输出格式
static final String DEFAULT_BANNER_LOCATION = "banner.txt";
static final String[] IMAGE_EXTENSION = { "gif", "jpg", "png" };
1.3.3、创建IOC容器
// 创建IOC容器
context = createApplicationContext();
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
// 根据Web应用类型决定实例化哪个IOC容器
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) {
// 抛异常
}
}
// 通过反射创建IOC容器,在这里beanFactory就被创建出来了
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
1.3.4、prepareContext
// 初始化IOC容器
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
// 将创建好的应用环境设置到IOC容器中
context.setEnvironment(environment);
// IOC容器的后置处理
postProcessApplicationContext(context);
// 执行Initializer
applyInitializers(context);
// 回调SpringApplicationRunListeners的contextPrepared方法(在创建和准备ApplicationContext之后,但在加载之前)
listeners.contextPrepared(context);
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 注册两个组件,1个是Main方法的参数、还有一个是打印banner的
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
// 默认是false
((DefaultListableBeanFactory) beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// Load the sources
// 加载主启动类
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
// 注册主启动类
load(context, sources.toArray(new Object\[0\]));
listeners.contextLoaded(context);
}
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
// 注册BeanName生成器,默认是null
if (this.beanNameGenerator != null) {
context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
this.beanNameGenerator);
}
// 设置资源加载器和类加载器,默认是null
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());
}
}
protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}
public Set<Object> getAllSources() {
Set<Object> allSources = new LinkedHashSet<>();
// 这就是之前赋值过的主启动类
if (!CollectionUtils.isEmpty(this.primarySources)) {
allSources.addAll(this.primarySources);
}
// 默认为空
if (!CollectionUtils.isEmpty(this.sources)) {
allSources.addAll(this.sources);
}
return Collections.unmodifiableSet(allSources);
}
protected void load(ApplicationContext context, Object\[\] sources) {
// 先获取BeanDefinitionRegistry,获取的实际就是IOC容器
// 进去分析下创建方法,发现创建了几个关键的组件
BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
// 设置beanName生成器,debug发现此时还没有注册
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
// 为null
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
// 为null
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
// 这边分析了下好像就是讲主启动类作为bean注册到了BeanDefinition中
loader.load();
}
1.3.5、callRunners
如果要在SpringBoot框架一启动完成就做某件事情,可以利用启动加载器
// 启动加载器的实现方式1,同等Order下ApplicationRunner的run方法先执行
@Component
@Order(1)
public class FirstApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("FirstApplicationRunner run");
}
}
// 启动加载器的实现方式2
@Component
@Order(1)
public class FirstCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("FirstCommandLineRunner run");
}
}
// 调用启动加载器,在容器启动完成之后做一些事情
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);
}
}
}
来源:oschina
链接:https://my.oschina.net/liwanghong/blog/3167302