一. 启动原理分析
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
这是一个标准的springboot启动项目的,首先从@SpringBootApplication这个注解开始解读,阅读过源码发现这其实就是一个集合了多个spring注解的自定义注解(这也是springboot的产生原因,为了更敏捷地开发spring应用),源码如下:
@Target(ElementType.TYPE) //注解适用范围,其中TYPE用于描述类、接口(包括主借类型)或enum声明
@Retention(RetentionPolicy.RUNTIME)//注解的生命周期,保留到class文件中(也就是说该注解在什么时期可见)
@Documented //表明这个注解应该被javadoc记录
@Inherited //子类可以继承该注解
@SpringBootConfiguration //进入该注解可以发现继承了configuration,表示当前是注解类
@EnableAutoConfiguration //开启了sringboot的注解功能,springboot的四大神奇之一,其借助@import的帮助
@ComponentScan(excludeFilters = @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class)) //扫描路劲设置(具体待确认)
public @interface SpringBootApplication {
......
}
通过源码阅读可以发现上述注解中最主要其实就是@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan,三个注解作用可自行查看详细介绍。
下面从这个run方法开始跟踪,
SpringApplication.run(Application.class, args);
//source就是对应启动类的class
public static ConfigurableApplicationContext run(Object source, String... args) {
return run(new Object[] { source }, args);
}
//SpringApplication初始化解读如下:
//第一步:调用构造函数
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
return new SpringApplication(sources).run(args);
//通过构造函数生成一个新的SpringApplication,再调用它的run方法
}//第二步:构造函数调用初始化方法initialize,参数就是启动类的class
public SpringApplication(Object... sources) {
initialize(sources);
}/*-----------------------------------------------//初始化方法解读----------------------------------------------------------------------------------*/
@SuppressWarnings({ "unchecked", "rawtypes" })
private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
/*判断是否为web应用,通过deduceMainApplicationClass方法判断是否加载的有{
"javax.servlet.Servlet","org.springframework.web.context.ConfigurableWebApplicationContext" }*/
this.webEnvironment = deduceWebEnvironment();
从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer;
然后保存起来*/
setInitializers((Collection)getSpringFactoriesInstances(ApplicationContextInitializer.class));
/* 从spring.factories文件中找出key为ApplicationListener的类并实例化后设置到SpringApplication的listeners属性中。这个过程就是找出所有的应用程序事件监听器*/
setListeners((Collection)getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();//获取到main方法所在的类
}/*--------------------------------------------------------------------------------------------------------------------------------------------------------------*/
//获取所有实例
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// 通过classLoader 从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer集合,
//确保类不重复
Set<String> names = new LinkedHashSet<String>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,//创建实例
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);//实例排序
return instances;
}/*-----------------------------------------------------------------------------------------------------------------------------------------------------*/
// loadFactoryNames获取所有的的ApplicationContextInitializer
/*通过给定的类加载器classLoader 从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer*/
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
try {
/*获取所有jar下面的META-INF/spring.factories 文件路径例如: jar:file:/C:/Users/Administrator/.m2/repository/org/springframework/boot/spring-boot/1.5.10.RELEASE/spring-boot-1.5.10.RELEASE.jar!/META-INF/spring.factories
*/
Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
List<String> result = new ArrayList<String>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
//从给定资源加载属性(配置文件例如:.../spring.factories)
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
//读取配置文件中的ApplicationContextInitializer
String factoryClassNames = properties.getProperty(factoryClassName);
result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
}
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
"] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
/*---------------------------------------------------initialize()初始化方法结束,开始执行run-----------------------------------------------*/
public ConfigurableApplicationContext run(String... args) { //开启监听(stopWatch)用来记录任务的启动 结束时间,是一个非线程的安全的,如果自己使用要考虑多线程的情况. StopWatch stopWatch = new StopWatch(); stopWatch.start(); //声明IOC容器 ConfigurableApplicationContext context = null; //设置headless 略 configureHeadlessProperty(); //用SpringApplicationRunListeners来加载ApplicationListener中的业务. SpringApplicationRunListeners listeners = getRunListeners(args); listeners.started(); try { //封装命令行参数 ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); //准备环境 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); //控制台打印Spring banner图标 Banner printedBanner = printBanner(environment); //创建ApplicationContext;决定创建web的ioc还是普通的ioc context = createApplicationContext(); /*准备上下文环境:将environment保存到ioc中;applyInitializers():回调之前保存的所有的ApplicationContextInitializer的initialize方法回调所有的SpringApplicationRunListener的contextPrepared();prepareContext运行完成以后回调所有的SpringApplicationRunListener的contextLoaded();*/ prepareContext(context, environment, listeners, applicationArguments, printedBanner); /*刷新容器:ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat);Spring注解版。扫描,创建,加载所有组件的地方;(配置类,组件,自动配置)*/ refreshContext(context);//IOC创建完毕 /*从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调 ApplicationRunner先回调,CommandLineRunner再回调*/ afterRefresh(context, applicationArguments); //所有的SpringApplicationRunListener回调finished方法 listeners.finished(context, null); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } return context; } catch (Throwable ex) { handleRunFailure(context, listeners, ex); throw new IllegalStateException(ex); } }
/*----------------------------------------------获取环境prepareEnvironment()方法解读------------------------------------------------------------*/
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { // 获取或者生成环境 ConfigurableEnvironment environment = getOrCreateEnvironment(); // 配置环境 configureEnvironment(environment, applicationArguments.getSourceArgs()); //创建环境完成后回调SpringApplicationRunListener.environmentPrepared();表示环境准备完成 listeners.environmentPrepared(environment); if (isWebEnvironment(environment) && !this.webEnvironment) { environment = convertToStandardEnvironment(environment); } return environment; }
/*-------------------------------------------------------准备上下文环境 prepareContext()-----------------------------------------------------------*/
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {//给IOC容器赋值environment
context.setEnvironment(environment);//IOC后置处理,注册了组件
postProcessApplicationContext(context);//回调之前保存的所有的ApplicationContextInitializer的initialize方法
applyInitializers(context);//执行所有Listeners的contextPrepared()方法
listeners.contextPrepared(context);
if (this.logStartupInfo) { //日志记录
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// 把命令行参数的类applicationArguments 注册到IOC容器
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
if (printedBanner != null) {
//注册打印的banner
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// 获取主类信息
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[sources.size()]));
//prepareContext运行完成以后回调所有的SpringApplicationRunListener的contextLoaded();
listeners.contextLoaded(context);
}
/*----------------getInitializers() :获取到之前获取的ApplicationContextInitializer 实例,执行initialize()方法---------------------*/
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);
}
}
/*--------------------------------------------------刷新容器refreshContext(context);-----------------------------------------------------*/
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备此上下文以进行刷新。
prepareRefresh();
// 告诉子类刷新内部bean工厂。
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//准备使用这个beanFatory
//配置工厂的标准上下文特性,
//*如上下文的类加载器和后置处理器。
prepareBeanFactory(beanFactory);
try {
// 允许在上下文子类中对bean工厂进行后处理。
postProcessBeanFactory(beanFactory);
// 调用工厂处理器在上下文中注册为bean。
invokeBeanFactoryPostProcessors(beanFactory);
//注册拦截Bean创建的Bean处理,这里只是注册,真正调用是再拿去Bean的时候 registerBeanPostProcessors(beanFactory);
// 初始化此上下文的消息源,即不同语言的消息体,国际化处理
initMessageSource();//初始化应用消息广播器,并放到applicationEventMulticaster bean中
initApplicationEventMulticaster();
//在特殊的context子类中初始化其他的特殊bean.
onRefresh();
// 在所有注册的bean中查找Listener bean,注册到消息广播中
registerListeners();
//创建所有非懒加载的单例类(并invoke BeanPostProcessors)finishBeanFactoryInitialization(beanFactory);
//完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人
finishRefresh();
}
catch (BeansException ex) {
.......}
}
/*-----------------------------------------------------afterRefresh(context, applicationArguments);------------------------------------------*/
protected void afterRefresh(ConfigurableApplicationContext context,
ApplicationArguments args) {
callRunners(context, args);
}
//获取ApplicationRunner 和 CommandLineRunner 并会调
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<Object>();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<Object>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}
调用SpringApplication.run()方法(时序图步骤3)
构造SpringApplicationRunListeners 实例(时序图步骤3.1.1)
发布ApplicationStartedEvent事件(时序图步骤3.1.2)
SpringApplicationRunListeners 实例准备环境信息(时序图步骤3.1.3)
创建ApplicationContext对象(时序图步骤3.1.4)
ApplicationContext实例准备环境信息(时序图步骤3.1.5)
刷新的上下文(时序图步骤3.1.6)
参考: https://www.jianshu.com/p/caa9cd010940
https://www.jianshu.com/p/464d04c36fb1
https://www.jianshu.com/p/64aac6461d5b
https://www.cnblogs.com/wudi-dudu/p/7871405.html
https://www.cnblogs.com/kaituorensheng/p/7105639.html