Spring Boot 源码解析
一. 启动类内容
public static void main(String[] args) {
// 实例化SpringApplication
SpringApplication sa = new SpringApplication(JARApplication.class);
// sa.addInitializers(); // 自定义加载器
// sa.addListeners(); // 自定义监听器
sa.run(args);
}
二. SpringApplication实例化解析
// 是否是web环境
private boolean webEnvironment;
// 用来判断是否是web环境的
private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
private final Set<Object> sources = new LinkedHashSet<Object>();
private List<ApplicationContextInitializer<?>> initializers;
private List<ApplicationListener<?>> listeners;
private Class<?> mainApplicationClass;
public SpringApplication(Object... sources) {
initialize(sources);
}
// 实例化方法
private void initialize(Object[] sources) {
// 将传入的"JARApplication"放入Set<Object> sources集合中。
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
// 判断是否是web环境
this.webEnvironment = deduceWebEnvironment();
// 创建并初始化ApplicationContextInitializer列表
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// 创建并初始化ApplicationListener列表
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
initialize方法做了下列内容
1. 将传入的"JARApplication"放入Set<Object> sources集合中。
2. 判断是否是web环境
private boolean deduceWebEnvironment() {
// 循环String[] WEB_ENVIRONMENT_CLASSES看是否存在。
for (String className : WEB_ENVIRONMENT_CLASSES) {
// 判断由提供的类名(类的全限定名)标识的类是否存在并可以加载
if (!ClassUtils.isPresent(className, null)) {
return false;
}
}
return true;
}
3. 创建并初始化ApplicationContextInitializer列表
public void setInitializers(
Collection<? extends ApplicationContextInitializer<?>> initializers) {
// 初始化一个ArrayList。
this.initializers = new ArrayList<ApplicationContextInitializer<?>>();
// 将所有的initializers传入
this.initializers.addAll(initializers);
}
// 获取initializer列表,type是ApplicationContextInitializer.class
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// 使用名称并确保唯一以防止重复, 获取要加载的initializer
Set<String> names = new LinkedHashSet<String>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 根据名称实例化,就是用反射创建对象,
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
// 排序
AnnotationAwareOrderComparator.sort(instances);
// 返回集合
return instances;
}
// 获取name
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
try {
// 获取配置文件路径。其实就是从Maven仓库中的spring-boot-1.4.3.RELEASE.jar以及spring-boot-autoconfigure-1.4.3.RELEASE.jar的META-INF/spring.factories中获取key为org.springframework.context.ApplicationContextInitializer的所有initializers全类名
// spring-boot.jar下的配置信息
// org.springframework.context.ApplicationContextInitializer=\
// org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
// org.springframework.boot.context.ContextIdApplicationContextInitializer,\
// org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
// org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer
// spring-boot-autoconfigure.jar下的配置信息
// org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
// org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer
// 默认是加载这6个初始化器
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();
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
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);
}
}
4. 创建并初始化ApplicationListener列表
// 与ApplicationContextInitializer初始化的步骤一致,获取的同样是默认配置文件下的ApplicationListener内容
5. 初始化主类mainApplicationClass
// 初始化主类方法
private Class<?> deduceMainApplicationClass() {
try {
// 调用的函数堆栈,这里解释下其实就是从main方法进来到SpringApplication方法,再到initialize方法再到deduceMainApplicationClass
// 那这个stackTrace就有4个元素。找到方法名是main的方法就是找到最开始的main方法,然后根据方法反射找到主类
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;
}
三. 添加自定义监听器、自定义初始化器
// 相当于在initializers或者listeners的数组中添加元素
public void setInitializers(
Collection<? extends ApplicationContextInitializer<?>> initializers) {
this.initializers = new ArrayList<ApplicationContextInitializer<?>>();
this.initializers.addAll(initializers);
}
四、启动核心run方法
/**
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
// 创建计时器
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
// 设置awt系统属性。
configureHeadlessProperty();
// 获取SpringApplicationRunListeners
SpringApplicationRunListeners listeners = getRunListeners(args);、
// 启动listeners
listeners.starting();
try {
// 创建ApplicationArguments
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
// 创建并初始化ConfigurableEnvironment
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
// 打印banner
Banner printedBanner = printBanner(environment);
// 创建ConfigurableApplicationContext
context = createApplicationContext();
// 创建FailureAnalyzers对象
analyzers = new FailureAnalyzers(context);
// 准备ConfigurableApplicationContext
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
// 刷新ConfigurableApplicationContext
refreshContext(context);
// 刷新后动作
afterRefresh(context, applicationArguments);
// 发布finish事件
listeners.finished(context, null);
// 定时器stop
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
1. 创建计时器
2. 设置awt系统属性
3. 获取SpringApplicationRunListeners
// 与之前初始化initializer和listener一样,从spring-boot的jar包的配置文件spring.factories中读取SpringApplicationRunListeners全类名的配置信息,之后创建该对象
// 配置信息内容。EventPublishingRunListener用来发布事件,触发监听器
// org.springframework.boot.context.event.EventPublishingRunListener
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
// 实例化EventPublishingRunListener放入SpringApplicationRunListeners中
SpringApplicationRunListeners(Log log,
Collection<? extends SpringApplicationRunListener> listeners) {
this.log = log;
this.listeners = new ArrayList<SpringApplicationRunListener>(listeners);
}
// 这里是EventPublishingRunListener的源码
private final SpringApplication application;
private final String[] args;
private final SimpleApplicationEventMulticaster initialMulticaster;
public EventPublishingRunListener(SpringApplication application, String[] args) {
// 这个是把刚实例化号的SpringApplication传入,里边有所有的listener包括自定义的
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
// 将所有的listener都添加到initialMulticaster示例中,这样当initialMulticaster发布事件时,监听器监听到该时间就会做出相应的动作。
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
4. 启动listeners
// SpriongApplicationRunListener的starting方法,会调用它包含的所有的listener的starting方法,这里listener只有一个就是EventPublishingRunListener
public void starting() {
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}
// EventPublishingRunListener的启动方法。回忆一下,initialMulticaster中已经加载了SpringApplication中所有的listener
@Override
@SuppressWarnings("deprecation")
public void starting() {
// 广播,所有监听了该事件的监听器都会执行相应的方法。
this.initialMulticaster
.multicastEvent(new ApplicationStartedEvent(this.application, this.args));
}
5. 创建ApplicationArguments
// 创建的过程,source会多层实例化,source的父类是SimpleCommandLinePropertySource的父类是CommandLinePropertySource的父类是EnumerablePropertySource的父类是PropertySource
public DefaultApplicationArguments(String[] args) {
Assert.notNull(args, "Args must not be null");
this.source = new Source(args);
this.args = args;
}
// 调用多个父类构造参数,执行到最后的结果是args和source。
// source的结果是 T source = CommandLineArgs;
class CommandLineArgs {
// optionArgs就是key,values的结果。举例:args = {--spring.output.ansi.enabled=always}, optionArgs = k:spring.output.ansi.enabled, v:{always}。其中v是一个list。
private final Map<String, List<String>> optionArgs = new HashMap<String, List<String>>();
private final List<String> nonOptionArgs = new ArrayList<String>();
6. 创建并初始化ConfigurableEnvironment
//
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
// 创建一个ConfigurableEnvironment实例
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 配置ConfigurableEnvironment实例
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 发布ApplicationEnvironmentPreparedEvent事件
listeners.environmentPrepared(environment);
if (!this.webEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertToStandardEnvironmentIfNecessary(environment);
}
return environment;
}
// (1)、创建ConfigurableEnvironment的代码
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
// 这里webEnvironment是true,所以创建的是StandardServletEnvironment
if (this.webEnvironment) {
return new StandardServletEnvironment();
}
return new StandardEnvironment();
}
// 实例化StandardServletEnvironment 会先调用其父类AbstractEnvironment的构造器
// MutablePropertySources是PropertySources的子类,PropertySources中的一个属性propertySourceList会存放所有的属性源PropertySource
private final MutablePropertySources propertySources = new MutablePropertySources(this.logger);
private final ConfigurablePropertyResolver propertyResolver =
new PropertySourcesPropertyResolver(this.propertySources);
public AbstractEnvironment() {
// 调用该方法,为propertySources增加PropertySource
customizePropertySources(this.propertySources);
if (logger.isDebugEnabled()) {
logger.debug("Initialized " + getClass().getSimpleName() + " with PropertySources " + this.propertySources);
}
}
// StandardServletEnvironment中的实例化方法,增加两个属性源,
@Override
protected void customizePropertySources(MutablePropertySources propertySources) {
// 增加name为servletConfigInit-Params的属性源
propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
// 增加name为servletContextInitParams的属性源
propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));
}
// 调用StandardServletEnvironment父类的customizePropertySources方法
super.customizePropertySources(propertySources);
}
// 父类的customizePropertySources方法,也是增加了两个属性源
@Override
protected void customizePropertySources(MutablePropertySources propertySources) {
// 增加了SystemProperties的属性源,值为一个Map,存放了jvm的系统属性例如java.runtime.name - Java(TM) SE Runtime Environment这种键值对,
// 其中在启动jvm的参数中设置了server.port=8088,这个值就被放到这个map中了,里边存放了55个键值对
propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
// 这个属性源为SystemEnvironmentPropertySource,主要存放一些系统环境属性,比如从环境变量文件中读取的M2_HOME等。里边暂时存放了21个键值对
propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}
// 到这里ConfigurableEnvironment的示例就创建成功了。里边总共包含了下列东西:
// 1、 不包含任何元素的LinkedHashSet,name为activeProfiles;
// 2、 一个包含default元素的LinkedHashSet,name是defaultProfiles。
// 3、 一个MutablePropertySources,其中包含4个属性源。
// 4、 一个PropertySourcesPropertyResolver属性,主要用于解析属性源,其内部包含3描述的MutablePropertySources的属性。以及用于解析属性源的其他属性。
// (2).配置ConfigurableEnvironment实例的代码,其实就是配置activeProfiles和PropertySources两个list。
protected void configureEnvironment(ConfigurableEnvironment environment,
String[] args) {
// 配置PropertySources
configurePropertySources(environment, args);
// 配置activeProfiles
configureProfiles(environment, args);
}
// 配置PropertySources的源码
protected void configurePropertySources(ConfigurableEnvironment environment,
String[] args) {
// 实例化MutablePropertySources
MutablePropertySources sources = environment.getPropertySources();
// 将default属性源加入
if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
sources.addLast(
new MapPropertySource("defaultProperties", this.defaultProperties));
}
// args参数解析并加入Sources中
if (this.addCommandLineProperties && args.length > 0) {
String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
if (sources.contains(name)) {
PropertySource<?> source = sources.get(name);
CompositePropertySource composite = new CompositePropertySource(name);
composite.addPropertySource(new SimpleCommandLinePropertySource(
name + "-" + args.hashCode(), args));
composite.addPropertySource(source);
sources.replace(name, composite);
}
else {
// 创建了一个SimpleCommandLinePropertySource,并将该属性源放入source的首部,表明优先级最高
sources.addFirst(new SimpleCommandLinePropertySource(args));
}
}
}
// 配置activeProfiles的源码,其实就是读取spring.profiles.active所指定的配置文件
protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
// 先get一下,确保它们已初始化
environment.getActiveProfiles(); // ensure they are initialized
// But these ones should go first (last wins in a property key clash)
Set<String> profiles = new LinkedHashSet<String>(this.additionalProfiles);
profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
environment.setActiveProfiles(profiles.toArray(new String[profiles.size()]));
}
// (3). 发布 ApplicationEnvironmentPreparedEvent事件的代码与starting事件发布类似
public void environmentPrepared(ConfigurableEnvironment environment) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.environmentPrepared(environment);
}
}
// 所有监听了该时间的监听器执行相应的逻辑。这些监听器监听之后主要做了一件事,就是读取配置文件application.properties,
// 并把这些信息存储到一个name为applicationConfigurationProperties的属性源中,并将该属性源置于整个属性源列表的最后。
7. 打印banner
这个主要用来打印图标和版本号,可以自己定制,这里不再解析。
8. 创建ConfigurableApplicationContext
/**
* The class name of application context that will be used by default for non-web
* environments.
*/
public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
+ "annotation.AnnotationConfigApplicationContext";
/**
* The class name of application context that will be used by default for web
* environments.
*/
public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework."
+ "boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext";
// 主要是为conctextClass赋值,使用了SpringBoot自己的AnnotationConfigEmbeddedWebApplicationContext。
// 之后通过反射实例化ApplicationContext
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
// 如果是web项目读取AnnotationConfigEmbeddedWebApplicationContext值
contextClass = Class.forName(this.webEnvironment
? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass",
ex);
}
}
// 通过反射实例化ConfigurableApplicationContext
return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
}
9. 准备ConfigurableApplicationContext
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
// 加载配置
context.setEnvironment(environment);
// 传入context
postProcessApplicationContext(context);
// (1). 执行初始化器
applyInitializers(context);
// 广播该事件
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
// 添加springApplicationArguments的单例Bean
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// (2). Load the sources,加载配置
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[sources.size()]));
listeners.contextLoaded(context);
}
// (1). 执行初始化器
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);
}
}
// (2). 加载配置,其中source参数只包含主类,Application.class
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug(
"Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
// 将主类注册到ApplicationContext中
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();
}
// 这里需要注意,在注册到主类时有个校验,是否是Component注解。所以主类要有@Component
10. 刷新ConfigurableApplicationContext
// 调用链过长,这里直接看最终的方法,方法内部注解比较完善
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.准备刷新此Context
prepareRefresh();
// Tell the subclass to refresh the internal bean factory. 告诉子类刷新内部bean工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context. 准备bean工厂以便在Context中使用
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses. 允许Context子类中对bean工厂进行后处理
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context. 在Context中调用注册为bean的工厂处理器。
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation. 注册拦截bean创建的bean处理器
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context. Context中初始化消息源
initMessageSource();
// Initialize event multicaster for this context.初始化多事件源
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses. 初始化特定的其他特殊bean
// 该方法创建了一个内嵌的servlet容器,用于执行web应用。默认是创建Tomcat-EmbeddedServletContainer
onRefresh();
// Check for listener beans and register them. 检查监听器,并注册
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons. 实例化剩余的所有非延迟加载的单例
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event. 发布refresh finish事件
// 该方法中发布了ContextRefreshedEvent事件,所有监听了该事件的监听器开始执行,
// 然后启动Tomcat-EmbeddedServletContainer,启动完成后发布EmbeddedServletContainerInitializedEvent事件,
// 所有的监听了该事件的监听器开始执行
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
11. 容器刷新后动作
// 该方法几乎没做什么事,不做解析了。
afterRefresh(context, applicationArguments);
12. SpringApplicationRunListeners发布finish事件
// 发布ApplicationReadyEvent或ApplicationFailedEvent事件,所有监听了该事件的监听器执行逻辑。
listeners.finished(context, null);
13. 计时器停止计时
stopWatch.stop();
14. 补充步骤。 后期高级版本多了analyzers = new FailureAnalyzers(context);方法。
// 这个方法就是发初始化的FailureAnalyzer对象,如果是BeanFactoryAware类型的,则调用其setBeanFactory方法,需要注意的是,此时的bean,还没有加载,bean的加载过程还在后面,所以此时获取的beanFactory是没有bean属性的。