SpringBoot源码 - 启动
SpringBoot Application启动部分的源码阅读.
SpringApplication
常用的SpringApplication.run(Class, Args)
启动Spring应用, 创建或者更新ApplicationContext
静态方法run
使用source类实例化一个SpringApplication
实例, 并调用实例方法run
.
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
return new SpringApplication(sources).run(args);
}
初始化initialize
-
实例化的时候首先通过尝试加载
javax.servlet.Servlet
和org.springframework.web.context.ConfigurableWebApplicationContext
推断当前是否是web环境. -
然后从
spring.factories
获取ApplicationContextInitializer
的实现类. -
从
spring.factories
获取ApplicationListener
的实现类 -
推断出应用的启动类(包含main方法的类): 检查线程栈中元素的方法名是否是
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;
}
到此实例化就完成了.
实例方法run
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
//默认设置java.awt.headless为true
configureHeadlessProperty();
//从spring.factories中获取org.springframework.boot.SpringApplicationRunListener的实现类
SpringApplicationRunListeners listeners = getRunListeners(args);
//通过EventPublishingRunListener发布started事件
listeners.started();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//重点: 创建更新上下文对象
context = createAndRefreshContext(listeners, applicationArguments);
//上下文对象更新完调用
afterRefresh(context, applicationArguments);
//通过EventPublishingRunListener发布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);
}
}
SpringApplicationRunListener
监听SpringApplication
的run
方法. 通过SpringFactoriesLoader
加载, 实现时需要提供public的构造方法接受SpringApplication
和String[]
为参数.
事件的发生顺序为started -> environmentPrepared -> contextPrepared -> contextLoaded -> finished
.
SpringBoot默认使用EventPublishingRunListener
这个实现类, 将各个事件封装并发布出去, 最终被ApplicationListener
捕获.
public interface SpringApplicationRunListener {
void started();
void environmentPrepared(ConfigurableEnvironment environment);
void contextPrepared(ConfigurableApplicationContext context);
void contextLoaded(ConfigurableApplicationContext context);
void finished(ConfigurableApplicationContext context, Throwable exception);
}
创建并更新上下文对象createAndRefreshContext
private ConfigurableApplicationContext createAndRefreshContext(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
ConfigurableApplicationContext context;
// Create and configure the environment
//获取或创建环境实例, web环境使用StandardServletEnvironment, 非web环境使用StandardEnvironment
ConfigurableEnvironment environment = getOrCreateEnvironment();
//配置环境数据
//1. **commandLineArgs**属性从启动参数中解析, 格式"--name=value"
//2. 配置profiles. 有效的profile(通过**spring.profiles.active**配置) 和 通过SpringApplication.profiles()指定的额外profile
configureEnvironment(environment, applicationArguments.getSourceArgs());
//通过EventPublishingRunListener发布environmentPrepared事件
listeners.environmentPrepared(environment);
//如果是web环境, 将非web环境实例转换成web环境实例:
//使用有效的profile配置和jndiProperties, servletConfigInitParams, servletContextInitParams的配置.
if (isWebEnvironment(environment) && !this.webEnvironment) {
environment = convertToStandardEnvironment(environment);
}
//输出banner
if (this.bannerMode != Banner.Mode.OFF) {
printBanner(environment);
}
//创建上下文对象, 没有指定实现类的话(使用SpringApplicationBuilder.contextClass), 使用默认context类. 然后通过反射实例化上下文对象.
//1. web环境使用org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext
//2. org.springframework.context.annotation.AnnotationConfigApplicationContext
//初始化实例的时候会做很多事,
//1. 创建AnnotatedBeanDefinitionReader. 注册相关的Annotation Post Processor, 包括: ConfigurationClassPostProcessor(处理@Configuration标注的类), AutowiredAnnotationBeanPostProcessor, RequiredAnnotationBeanPostProcessor, CommonAnnotationBeanPostProcessor, PersistenceAnnotationBeanPostProcessor, EventListenerMethodProcessor, DefaultEventListenerFactory
//2. 创建ClassPathBeanDefinitionScanner. 扫描器, 扫描默认的过滤器@Service, @Component, @Registry, @Controller. 同时支持J2EE6的@ManagedBean和@Named
// Create, load, refresh and run the ApplicationContext
context = createApplicationContext();
//设置环境
context.setEnvironment(environment);
//后续的处理
postProcessApplicationContext(context);
//应用初始化器(ApplicationContextInitializer的实现类), 对上下文对象做更多初始化的操作, 比如:
//1. 添加BeanFactoryPostProcessor
//2 .设置上下文对象id
//3 .代理配置中context.initializer.classes指定的初始化类
//4. 添加listener, 在web容器启动后更新环境变量中的端口号(server.ports中的local.server.port)
applyInitializers(context);
//通过EventPublishingRunListener发布contextPrepared事件
listeners.contextPrepared(context);
//打印启动信息和有效的profile信息
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
//将ApplicationArguments实例注册到BeanFactory中, 名字为springApplicationArguments
// Add boot specific singleton beans
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
//从source(可以是Resource, Package, CharSequence或者Class. 从run方法进来的为Class)类加载Bean到上下文对象中
// Load the sources
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[sources.size()]));
//通过EventPublishingRunListener发布contextLoaded事件
listeners.contextLoaded(context);
//更新上下文对象, 调用ApplicationContext.refresh()方法
// Refresh the context
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
return context;
}
更新上下文 ApplicationContext.refresh()
- prepareRefresh 记录启动时间, 初始化上下文环境信息中的占位符, 检查必须的属性
- obtainFreshBeanFactory 重建内置的BeanFactory, 并加载bean定义
- prepareBeanFactory 初始化BeanFactory的标准上下文属性, 如BeanClassLoader, ExpressionResolver, PropertyEditorRegistrar, BeanPostProcessor, LoadTimeWeaverAwarePostProcessor等等.
- postProcessBeanFactory 标准初始化后修改上下文内置的BeanFactory
- invokeBeanFactoryPostProcessors
实例化并调用注册的
BeanFactoryPostProcessor
, 基于精确的顺序如果指定了顺序的话. 有些processor是操作Bean定义注册表的(如@Configuration
标注的类bean包含其他的bean定义), 会在常规的BeanFactoryPostProcessor
的检查发生之前. 在上下文对象的bean定义注册器进行了标准初始化之后进, 所有的常规bean定义都已经被加载了, 但是还没有bean被实例化. 在post-processiong之前可以添加更多的bean定义.@Configuration
标注的类中的bean定义会在此时假如到注册器中. - registerBeanPostProcessors
实例化并调用注册的
BeanPostProcessor
, 如果有顺序的话, 按照顺序来调用. - initMessageSource
初始化名为messageSource的
MessageSource
实例. - initApplicationEventMulticaster
初始化名为applicationEventMulticaster的
ApplicationEventMulticaster
实例, 应用可以用来注册应用事件的监听. - onRefresh 供子类实现添加更多的更新操作.
- registerListeners
通过applicationEventMulticaster注册
ApplicationListener
实现类的监听器. - finishBeanFactoryInitialization
进行上下文的BeanFactory初始化的收尾. 如提前初始化
LoadTimeWeaverAware
的bean, 冻结配置禁止修改bean定义, 实例化non-lazy-init的bean. - finishRefresh
完成更新, 调用
LifecycleProcessor.onRefresh()
, 发布ContextRefreshedEvent
事件, 将上下文实例暴露在MBean中.
ConfigurationClassPostProcessor
BeanFactoryPostProcessor
的实现类, 用于引导@Configuration
类.
默认情况下通过使用<context:annotation-config/>
或者<context:component-scan/>
注册.
注解
@SpringBootApplication
集合了@Configuration
, @EnableAutoConfiguration
和@ComponentScan
属性: exclude
, excludeName
, scanBasePackage
, scanBasePackageClass
@Configuration
类似旧版配置中的xml配置文件, 提供Bean的定义和引入其他xml配置. 分别通过@Bean
和@Import
实现.
在ApplicationContext.refresh()时是用ConfigurationClassPostProcessor
进行bean的实例化.
可以与@PropertySource
, @Autowired
, @Value
, @Profile
搭配使用.
@Configuration
@PropertySource("classpath:/com/acme/app.properties")
public class AppConfig {
@Value("${bean.name}") String beanName;
@Autowired DataSource dataSource;
@Bean
public MyBean myBean() {
return new MyBean(beanName);
}
@Configuration
@Profile("test")
static class DatabaseConfigTest {
@Bean
DataSource dataSource() {
return new EmbeddedDatabaseBuilder().build();
}
}
@Configuration
@Profile("production")
static class DatabaseConfigProduction {
@Bean
DataSource dataSource() {
return new EmbeddedDatabaseBuilder().build();
}
}
}
@EnableAutoConfiguration
开启Spring上下文对象的自动配置功能, 尝试去猜测和实例化你可能需要的bean.
这个功能是基于classPath来完成的. 比如: 项目中引用了tomcat-embedded.jar
, 你可能需要一个TomcatEmbeddedServletContainerFactory
实例, 除非定义了自己的EmbeddedServletContainerFactory
实例.
@ComponentScan
扫描使用@Configuration
标注的类, 类似于Spring XML的<context:component-scan>
元素.
使用basePackages
和basePackageClasses
属性来指定要扫描的包, 如果没有指定, 则默认从使用了该注解的类的包开始扫描.
@Import
提示@Configuration
有更多的类需要引入, 类似xml中的<import>
标签.
可以引入@Configuration
类, ImportSelector
的实现类和ImportBeanDefinitionRegistrar
的实现类, 还有常规的Component
类.
三者的处理方式不一样:
@Configuration
常规方式ImportSelector
会根据泛型类型从spring.factories找到对应的配置类.ImportBeanDefinitionRegistrar
可以实现在bean definition级别的处理 (@Bean
实例级别)
在引入@Configuration
类中使用@Bean
标注的实例, 可以通过@Autowired
注入. Bean和声明Bean的Configuration类本身都可以通过@Autowired
注入.
引入XML或者非Configuration, 使用@ImportResource
.