Spring Boot源码分析二(启动流程原理)
入口
**SpringApplication**的构造器设置应用类型设置初始化器设置监听器(Listener) SpringApplication.run方法
获取并启动监听器环境构建创建容器Spring容器前置处理
调用初始化器**加载启动指定类**通知监听器,容器已准备就绪 刷新上下文Spring容器后置处理发出结束执行的事件执行Runners
入口@SpringBootApplication public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } }
**SpringApplication.run(MyApplication.class, args);**跟进去
public static ConfigurableApplicationContext run(Class> primarySource, String... args) { return run(new Class>[] { primarySource }, args); } public static ConfigurableApplicationContext run(Class>[] primarySources, String[] args) { return new SpringApplication(primarySources).run(args); }
首先会 new 一个SpringApplication的实例,并将启动类作为参数传进去,执行他的run方法。
SpringApplication的构造器 设置应用类型主要通过类加载器判断 REACTIVE 相关的Class是否存在,如果不存在,则web环境即为 SERVLET 类型。这里设置好web环境类型,在后面根据类型初始化对应环境。
spring-boot-starter-web 的pom会引入Tomcat和spring-webmvc,如下
org.springframework.boot spring-boot-starter-tomcat2.6.2 compile org.springframework spring-webmvc5.3.14 compile
spring-webmvc中存在DispatcherServlet这个类,也就是我们以前SpringMvc的核心Servlet,通过类加载能加载DispatcherServlet这个类,那么我们的应用类型自然就是WebApplicationType.SERVLET
设置初始化器// 设置初始化器(Initializer),最后会调用这些初始化器 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
这个方法会尝试从类路径的meta-INF/spring.factories处读取相应配置文件,然后进行遍历,读取配置文件中Key为:org.springframework.context.ApplicationContextInitializer的value。以spring-boot-autoconfigure这个包为例,它的meta-INF/spring.factories部分定义如下所示:
这两个类名会被读取出来,然后放入到Set集合中,准备开始下面的实例化 *** 作:
// parameterTypes: 上一步得到的names集合 privateList createSpringFactoriesInstances(Class type, Class>[] parameterTypes, ClassLoader classLoader, Object[] args, Set names) { List instances = new ArrayList (names.size()); for (String name : names) { try { Class> instanceClass = ClassUtils.forName(name, classLoader); //确认被加载类是ApplicationContextInitializer的子类 Assert.isAssignable(type, instanceClass); Constructor> constructor = instanceClass.getDeclaredConstructor(parameterTypes); //反射实例化对象 T instance = (T) BeanUtils.instantiateClass(constructor, args); //加入List集合中 instances.add(instance); } catch (Throwable ex) { throw new IllegalArgumentException( "Cannot instantiate " + type + " : " + name, ex); } } return instances; }
确认被加载的类确实是org.springframework.context.ApplicationContextInitializer的子类,然后就是得到构造器进行初始化,最后放入到实例列表中。
因此,所谓的初始化器就是org.springframework.context.ApplicationContextInitializer的实现类,这个接口是这样定义的:
public interface ApplicationContextInitializer{ void initialize(C applicationContext); }
在Spring上下文被刷新之前进行初始化的 *** 作。典型地比如在Web应用中,注册Property Sources或者是激活Profiles。Property Sources比较好理解,就是配置文件。Profiles是Spring为了在不同环境下(如DEV,TEST,PRODUCTION等),加载不同的配置项而抽象出来的一个实体。
设置监听器(Listener)下面开始设置监听器:
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
我们还是跟进代码看看getSpringFactoriesInstances
// 这里的入参type是:org.springframework.context.ApplicationListener.class privateCollection extends T> getSpringFactoriesInstances(Class type) { return getSpringFactoriesInstances(type, new Class>[] {}); } private Collection extends T> getSpringFactoriesInstances(Class type, Class>[] parameterTypes, Object... args) { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // Use names and ensure unique to protect against duplicates Set names = new linkedHashSet ( SpringFactoriesLoader.loadFactoryNames(type, classLoader)); List instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; }
可以发现,这个加载相应的类名,然后完成实例化的过程和上面在设置初始化器时如出一辙,同样,还是以spring-boot-autoconfigure这个包中的spring.factories为例,看看相应的Key-Value:
org.springframework.context.ApplicationListener= org.springframework.boot.autoconfigure.BackgroundPreinitializer org.springframework.context.ApplicationListener= org.springframework.boot.ClearCachesApplicationListener, org.springframework.boot.builder.ParentContextCloserApplicationListener, org.springframework.boot.context.FileEncodingApplicationListener, org.springframework.boot.context.config.AnsiOutputApplicationListener, org.springframework.boot.context.config.ConfigFileApplicationListener, org.springframework.boot.context.config.DelegatingApplicationListener, org.springframework.boot.context.logging.ClasspathLoggingApplicationListener, org.springframework.boot.context.logging.LoggingApplicationListener, org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
这10个监听器会贯穿springBoot整个生命周期。至此,对于SpringApplication实例的初始化过程就结束了。
SpringApplication.run方法完成了SpringApplication实例化,开始调用 run 方法。
第一步:获取并启动监听器第二步:根据SpringApplicationRunListeners以及参数来准备环境第三步:创建上下文第四步:预处理上下文第五步:刷新上下文第六步:再刷新上下文第七步:发出结束执行的事件第八步:执行Runners 获取并启动监听器
获取监听器
private SpringApplicationRunListeners getRunListeners(String[] args) { Class>[] types = new Class>[] { SpringApplication.class, String[].class }; return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args), this.applicationStartup); }
这里仍然利用了getSpringFactoriesInstances方法来获取实例,大家可以看看前面的这个方法分析,从meta-INF/spring.factories中读取Key为org.springframework.boot.SpringApplicationRunListener的Values:
org.springframework.boot.SpringApplicationRunListener=
org.springframework.boot.context.event.EventPublishingRunListener
getSpringFactoriesInstances中反射获取实例时会触发EventPublishingRunListener的构造函数,我们来看看EventPublishingRunListener的构造函数:
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered { private final SpringApplication application; private final String[] args; //广播器 private final SimpleApplicationEventMulticaster initialMulticaster; public EventPublishingRunListener(SpringApplication application, String[] args) { this.application = application; this.args = args; this.initialMulticaster = new SimpleApplicationEventMulticaster(); Iterator var3 = application.getListeners().iterator(); while(var3.hasNext()) { ApplicationListener> listener = (ApplicationListener)var3.next(); //将上面设置到SpringApplication的十一个监听器全部添加到SimpleApplicationEventMulticaster这个广播器中 this.initialMulticaster.addApplicationListener(listener); } } //略... }
我们看到**EventPublishingRunListener里面有一个广播器,EventPublishingRunListener 的构造方法将SpringApplication的十一个监听器全部添加到SimpleApplicationEventMulticaster这个广播器中,**我们来看看是如何添加到广播器:
public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware { //广播器的父类中存放保存监听器的内部内 private final AbstractApplicationEventMulticaster.ListenerRetriever defaultRetriever = new AbstractApplicationEventMulticaster.ListenerRetriever(false); @Override public void addApplicationListener(ApplicationListener> listener) { synchronized (this.retrievalMutex) { Object singletonTarget = AopProxyUtils.getSingletonTarget(listener); if (singletonTarget instanceof ApplicationListener) { this.defaultRetriever.applicationListeners.remove(singletonTarget); } //内部类对象 this.defaultRetriever.applicationListeners.add(listener); this.retrieverCache.clear(); } } private class ListenerRetriever { //保存所有的监听器 public final Set> applicationListeners = new linkedHashSet(); public final SetapplicationListenerBeans = new linkedHashSet(); private final boolean preFiltered; public ListenerRetriever(boolean preFiltered) { this.preFiltered = preFiltered; } public Collection> getApplicationListeners() { linkedList> allListeners = new linkedList(); Iterator var2 = this.applicationListeners.iterator(); while(var2.hasNext()) { ApplicationListener> listener = (ApplicationListener)var2.next(); allListeners.add(listener); } if (!this.applicationListenerBeans.isEmpty()) { BeanFactory beanFactory = AbstractApplicationEventMulticaster.this.getBeanFactory(); Iterator var8 = this.applicationListenerBeans.iterator(); while(var8.hasNext()) { String listenerBeanName = (String)var8.next(); try { ApplicationListener> listenerx = (ApplicationListener)beanFactory.getBean(listenerBeanName, ApplicationListener.class); if (this.preFiltered || !allListeners.contains(listenerx)) { allListeners.add(listenerx); } } catch (NoSuchBeanDefinitionException var6) { ; } } } AnnotationAwareOrderComparator.sort(allListeners); return allListeners; } } //略... }
上述方法定义在SimpleApplicationEventMulticaster父类AbstractApplicationEventMulticaster中。关键代码为this.defaultRetriever.applicationListeners.add(listener);,这是一个内部类,用来保存所有的监听器。也就是在这一步,将spring.factories中的监听器传递到SimpleApplicationEventMulticaster中。我们现在知道EventPublishingRunListener中有一个广播器SimpleApplicationEventMulticaster,SimpleApplicationEventMulticaster广播器中又存放所有的监听器。
启动监听器
我们上面一步通过getRunListeners方法获取的监听器为EventPublishingRunListener,从名字可以看出是启动事件发布监听器,主要用来发布启动事件。
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered { private final SpringApplication application; private final String[] args; private final SimpleApplicationEventMulticaster initialMulticaster;
我们先来看看SpringApplicationRunListener这个接口
package org.springframework.boot; public interface SpringApplicationRunListener { // 在run()方法开始执行时,该方法就立即被调用,可用于在初始化最早期时做一些工作 void starting(); // 当environment构建完成,ApplicationContext创建之前,该方法被调用 void environmentPrepared(ConfigurableEnvironment environment); // 当ApplicationContext构建完成时,该方法被调用 void contextPrepared(ConfigurableApplicationContext context); // 在ApplicationContext完成加载,但没有被刷新前,该方法被调用 void contextLoaded(ConfigurableApplicationContext context); // 在ApplicationContext刷新并启动后,CommandLineRunners和ApplicationRunner未被调用前,该方法被调用 void started(ConfigurableApplicationContext context); // 在run()方法执行完成前该方法被调用 void running(ConfigurableApplicationContext context); // 当应用运行出错时该方法被调用 void failed(ConfigurableApplicationContext context, Throwable exception); }
SpringApplicationRunListener接口在Spring Boot 启动初始化的过程中各种状态时执行,我们也可以添加自己的监听器,在SpringBoot初始化时监听事件执行自定义逻辑,我们先来看看SpringBoot启动时第一个启动事件listeners.starting():
@Override public void starting() { //关键代码,先创建application启动事件`ApplicationStartingEvent` this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args)); }
这里先创建了一个启动事件ApplicationStartingEvent,我们继续跟进SimpleApplicationEventMulticaster,有个核心方法:
@Override public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); //通过事件类型ApplicationStartingEvent获取对应的监听器 for (final ApplicationListener> listener : getApplicationListeners(event, type)) { //获取线程池,如果为空则同步处理。这里线程池为空,还未没初始化。 Executor executor = getTaskExecutor(); if (executor != null) { //异步发送事件 executor.execute(() -> invokeListener(listener, event)); } else { //同步发送事件 invokeListener(listener, event); } } }
这里会根据事件类型ApplicationStartingEvent获取对应的监听器,在容器启动之后执行响应的动作。
环境构建ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
跟进去:
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) { // 获取对应的 ConfigurableEnvironment ConfigurableEnvironment environment = getOrCreateEnvironment(); // 配置 configureEnvironment(environment, applicationArguments.getSourceArgs()); ConfigurationPropertySources.attach(environment); listeners.environmentPrepared(bootstrapContext, environment); DefaultPropertiesPropertySource.moveToEnd(environment); Assert.state(!environment.containsProperty("spring.main.environment-prefix"), "Environment prefix cannot be set via properties."); bindToSpringApplication(environment); if (!this.isCustomEnvironment) { environment = convertEnvironment(environment); } ConfigurationPropertySources.attach(environment); return environment; }创建容器
context = createApplicationContext();
这里是根据webApplicationType 进行判断的,该类型为SERVLET类型,会通过反射装载对应的字节码,也就是AnnotationConfigServletWebServerApplicationContext 。webApplicationType之前在构造器中有获取过。
Spring容器前置处理prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);调用初始化器
这里用到了在创建SpringApplication实例时设置的初始化器了,依次对它们进行遍历,并调用initialize方法。当然,我们也可以自定义初始化器,并实现initialize方法,然后放入 meta-INF/spring.factories 配置文件中 key 为org.springframework.context.ApplicationContextInitializer的value中,这里我们自定义的初始化器 就会被调用,使我们项目初始化的一种方式。
加载启动指定类这里也就是获取 this.primarySources 属性,也就是我们的启动类 MyApplication.class,接着看 load(context, sources.toArray(new Object[0])); 方法。
后续会出一篇文章详细介绍启动类是如何加载,以及自动化配置开启的详细流程。
通知监听器,容器已准备就绪listeners.contextLoaded(context);
这里主要针对一些日志等监听器的响应处理。
刷新上下文refreshContext(context);
这行到这里,SpringBoot相关的处理工作已经结束,接下的工作就交给了Spring。
refresh 方法是实现ioc 和 aop的关键,后续也会出文章进行详细分析。
Spring容器后置处理afterRefresh(context, applicationArguments);
扩展接口,设计模式中的模板方法,默认为空实现。如果有自定义需求,可以重写该方法。比如打印一些启动结束log,或者一些其他后置处理。
发出结束执行的事件listeners.started(context, timetakenToStartup);
获取EventPublishingRunListener监听器,并执行其started方法,并且将创建的Spring容器传进去了,创建一个ApplicationStartedEvent事件,并执行ConfigurableApplicationContext 的publishEvent方法,也就是说这里是在Spring容器中发布事件,并不是在SpringApplication中发布事件,和前面的starting是不同的,前面的starting是直接向SpringApplication中的11个监听器发布启动事件。
执行RunnerscallRunners(context, applicationArguments);
spring boot提供的2个供用户自己拓展的接口:ApplicationRunner和CommandLineRunner。实现其run方法,并注入到Spring容器中,在SpringBoot启动完成后,会执行所有的runner的run方法。可以在容器启动完毕后(上下文刷新后)执行,做一些类似数据初始化的 *** 作。
private void callRunners(ApplicationContext context, ApplicationArguments args) { List
两个区别在于入参不同,可以根据自己的实际情况进行选择。
public interface CommandLineRunner { void run(String... args) throws Exception; } public interface ApplicationRunner { void run(ApplicationArguments args) throws Exception; }
CommandLineRunner中执行参数是原始的java启动类main方法的String[] args字符串数组参数;ApplicationRunner中的参数经过处理提供一些方法例如: List
} if (runner instanceof CommandLineRunner) { callRunner((CommandLineRunner) runner, args); } } }
两个区别在于入参不同,可以根据自己的实际情况进行选择。 ```java public interface CommandLineRunner { void run(String... args) throws Exception; } public interface ApplicationRunner { void run(ApplicationArguments args) throws Exception; }
CommandLineRunner中执行参数是原始的java启动类main方法的String[] args字符串数组参数;ApplicationRunner中的参数经过处理提供一些方法例如: List
根据名称获取值list,java 启动命令中 --foo=bar --foo=baz,则根据foo参数名返回list["bar", "baz"]
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)