您现在的位置是:首页 >技术教程 >spring boot原理分析网站首页技术教程
spring boot原理分析
总体流程
prepareEnvironment里会生成基本的propertySource列表,当然后续还可能会改,比如apollo会在refreshContext时添加自己的propertySource。
prepareContext里会调initializer初始化ApplicationContext,接着加载bean定义。
refreshContext是重中之重,最终会调用到ApplicationContext的refresh方法,它会创建ConfigurableListableBeanFactory类型的bean管理类对象,在此之上做各种定制处理,包括:
- BeanFactoryPostProcessor,spring容器加载了bean的定义文件之后,在bean实例化之前执行的定制行为
- BeanPostProcessor,在spring容器实例化bean之后,在执行bean的初始化方法前后,添加定制行为
spring.factories配置文件
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.sources = new LinkedHashSet();
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.addConversionService = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = new HashSet();
this.isCustomEnvironment = false;
this.lazyInitialization = false;
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//从spring.factories文件中找出key为ApplicationContextInitializer的类并实例化后设置到SpringApplication的initializers属性中。这个过程也就是找出所有的应用程序初始化器
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
从spring.factories文件中找出key为ApplicationListener的类并实例化后设置到SpringApplication的listeners属性中。这个过程就是找出所有的应用程序事件监听器
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
//这里就是咱们的XXXApplication类
this.mainApplicationClass = this.deduceMainApplicationClass();
}
spring.factories的作用:
其中指定的 系统组件可在springboot启动时加载,比如:
其中的ApplicationContextInitializer和ApplicationListener是无条件加载。
其中的@Configuration组件则依赖@EnableAutoConfiguration注解才会加载。但一旦我们配置了@EnableAutoConfiguration,这些@Configuration组件就可以无视@ComponentScan规定的扫描路径(默认只是我们的业务包),强行加载。
springboot机制会遍历整个 spring-boot 项目的 classpath 下 的 spring.factories文件。也就是说我们可以在自己的 jar 中配置 spring.factories 文件,不会影响到其它地方的配置,也不会被别人的配置覆盖。
spring-boot-autoconfigure里的spring.factories的例子:
# Initializers
org.springframework.context.ApplicationContextInitializer=
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
# Application Listeners
org.springframework.context.ApplicationListener=
org.springframework.boot.autoconfigure.BackgroundPreinitializer
# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener
# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=
org.springframework.boot.autoconfigure.condition.OnBeanCondition,
org.springframework.boot.autoconfigure.condition.OnClassCondition,
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,
ApplicationEvent
SpringApplication启动事件列表:
- ApplicationStartingEvent:SpringApplication准备启动事件
- ApplicationEnvironmentPreparedEvent :SpringApplication环境准备事件
- ApplicationContextInitializedEvent:ApplicationContext初始化完成事件
- ApplicationPreparedEvent :ApplicationContext加载bean定义完成事件
- ApplicationStartedEvent :ApplicationContext实例化bean完成事件
- ApplicationReadyEvent : SpringApplication就绪事件(可以提供服务了)
- ApplicationFailedEvent : SpringApplication启动失败事件
当然,Spring Boot还有其他事件,例如:
WebServerInitializedEvent事件
30s一次的eureka心跳事件:
RefreshScopeRefreshedEvent
ApplicationRunListener
ApplicationRunListener里会持有所有的ApplicationListener:
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
//ApplicationEventMulticaster其实是SimpleApplicationEventMulticaster
this.initialMulticaster = new SimpleApplicationEventMulticaster();
Iterator var3 = application.getListeners().iterator();
while(var3.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var3.next();
//持有所有的ApplicationListener
this.initialMulticaster.addApplicationListener(listener);
}
}
ApplicationListener
我们可以派生GenericApplicationListener类,实现自己的自定义ApplicationListener,只要实现两个方法即可:
- supportsEventType
- onApplicationEvent
这是GenericApplicationListener的定义:
public interface GenericApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {
/**
* Determine whether this listener actually supports the given event type.
* @param eventType the event type (never {@code null})
*/
boolean supportsEventType(ResolvableType eventType);
......
/**
* Determine this listener's order in a set of listeners for the same event.
* <p>The default implementation returns {@link #LOWEST_PRECEDENCE}.
*/
@Override
default int getOrder() {
return LOWEST_PRECEDENCE;
}
}
一些用于spring启动阶段的ApplicationListener只能通过spring.factories文件配置生效,spring启动完成后的ApplicationEvent则可通过bean注册ApplicationListener来响应。
常见的ApplicationListener列表:
0 = {BootstrapApplicationListener@2943}
1 = {LoggingSystemShutdownListener@2944}
2 = {CloudFoundryVcapEnvironmentPostProcessor@2945}
3 = {ConfigFileApplicationListener@2946}
4 = {AnsiOutputApplicationListener@2947}
5 = {LoggingApplicationListener@2948}
6 = {BackgroundPreinitializer@2949}
7 = {ClasspathLoggingApplicationListener@2950}
8 = {RestartListener@2951}
9 = {CustomizedAppListener@2952} //这个是我用来测试的listener
10 = {DelegatingApplicationListener@2953}
11 = {ParentContextCloserApplicationListener@2954}
12 = {EnableEncryptablePropertiesBeanFactoryPostProcessor@2955}
13 = {ServiceApplicationStartingListener@2956}
14 = {ClearCachesApplicationListener@2957}
15 = {FileEncodingApplicationListener@2958}
16 = {LiquibaseServiceLocatorApplicationListener@2959}
BootstrapApplicationListener的问题我们在“环境配置加载了两次”的地方再讲,这块比较复杂。
ConfigFileApplicationListener和EnableEncryptablePropertiesBeanFactoryPostProcessor,前者加载application.yml配置文件,后者则对配置进行加密(但不是在prepareEnvironment里做的,而是在refreshContext里做的)。
ApplicationContextInitializer
ApplicationContext容器初始化器,接口如下:
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
void initialize(C applicationContext);
}
我们也可以派生该接口,定制我们自己的行为,比如ApolloApplicationContextInitializer,负责构建apollo的ApolloBootstrapPropertySources:
public void initialize(ConfigurableApplicationContext context) {
//检查apollo.bootstrap.enabled是否设置,设置了才做真正的初始化动作
ConfigurableEnvironment environment = context.getEnvironment();
if (!(Boolean)environment.getProperty("apollo.bootstrap.enabled", Boolean.class, false)) {
logger.debug("Apollo bootstrap config is not enabled for context {}, see property: ${{}}", context, "apollo.bootstrap.enabled");
} else {
logger.debug("Apollo bootstrap config is enabled for context {}", context);
this.initialize(environment);
}
}
protected void initialize(ConfigurableEnvironment environment) {
if (environment.getPropertySources().contains("ApolloBootstrapPropertySources")) {
//如果环境里的ApolloBootstrapPropertySources已就绪,打个日志就结束
DeferredLogger.replayTo();
} else {
String namespaces = environment.getProperty("apollo.bootstrap.namespaces", "application");
logger.debug("Apollo bootstrap namespaces: {}", namespaces);
List<String> namespaceList = NAMESPACE_SPLITTER.splitToList(namespaces);
ConfigUtil configUtil = (ConfigUtil)ApolloInjector.getInstance(ConfigUtil.class);
Object composite;
//如无ApolloBootstrapPropertySources,创建一个
if (configUtil.isPropertyNamesCacheEnabled()) {
composite = new CachedCompositePropertySource("ApolloBootstrapPropertySources");
} else {
composite = new CompositePropertySource("ApolloBootstrapPropertySources");
}
Iterator i$ = namespaceList.iterator();
while(i$.hasNext()) {
String namespace = (String)i$.next();
//从apollo服务器获得namespace下的配置项列表
Config config = ConfigService.getConfig(namespace);
//将apollo的配置项加到ApolloBootstrapPropertySources里去
((CompositePropertySource)composite).addPropertySource(this.configPropertySourceFactory.getConfigPropertySource(namespace, config));
}
//最后将ApolloBootstrapPropertySources放到propertySource列表的开头(表示优先级最高)
environment.getPropertySources().addFirst((PropertySource)composite);
}
}
注意:ApplicationContextInitializer的配置也要通过spring.factories文件生效。
常见的initializer列表:
1 = {BootstrapApplicationListener$AncestorInitializer@5536}
2 = {SharedMetadataReaderFactoryContextInitializer@3017}
3 = {ApolloApplicationContextInitializer@3018}
4 = {DelegatingApplicationContextInitializer@3019}
6 = {ContextIdApplicationContextInitializer@3021}
7 = {ConditionEvaluationReportLoggingListener@3022}
8 = {ConfigurationWarningsApplicationContextInitializer@3023}
9 = {RSocketPortInfoApplicationContextInitializer@3024}
10 = {ServerPortInfoApplicationContextInitializer@3025}
11 = {PropertySourceBootstrapConfiguration@5537}
12 = {EnvironmentDecryptApplicationInitializer@5538}
13 = {EnableEncryptablePropertiesConfiguration$$EnhancerBySpringCGLIB$$cff3bf92@5539}
refreshContext阶段
refreshContext实际调用的是AbstractApplicationContext.refresh方法,后者定义如下:
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
//处理BeanFactoryPostProcessor
this.invokeBeanFactoryPostProcessors(beanFactory);
//处理BeanPostProcessor
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
//处理其他的bean
this.onRefresh();
this.registerListeners();
//实例化所有的bean
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
ConfigurableListableBeanFactory
默认实现是DefaultListableBeanFactory类,它其实同时实现了ConfigurableListableBeanFactory和BeanDefinitionRegistry两个接口
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry
本质上,它是一个bean的管理类,负责:
- bean定义的增删改查
- bean实例的查找与创建(其getBean方法在找不到bean实例时会调用init-method去创建出实例来)
bean定义的后处理
实现在PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors里。如前所述,它在refreshContext阶段里调用。
bean定义的后处理放在了实现下面两个接口的特殊bean里:
- BeanFactoryPostProcessor:用来修改Spring容器中已经存在的bean,使用ConfigurableListableBeanFactory对bean进行处理
- BeanDefinitionRegistryPostProcessor:继承BeanFactoryPostProcessor,使用BeanDefinitionRegistry对bean的定义进行处理
考虑到默认实现DefaultListableBeanFactory类,既是ConfigurableListableBeanFactory,也是BeanDefinitionRegistry,所以传给BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor的其实是同一个beanFactory对象。
注意
:
BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor也都是注册到ApplicationContext里的bean(不声明为bean不能被ApplicationContext识别!),不过是用来修改普通bean行为的“特殊bean”,所以它们的实例化时间肯定早于普通bean
执行顺序:BeanDefinitionRegistryPostProcessor接口的postProcessBeanDefinitionRegistry方法 早于
BeanFactoryPostProcessor接口的postProcessBeanFactory方法
两者的执行时机都是在普通bean实例化之前
与BeanDefinitionRegistryPostProcessor只能修改bean定义不同,BeanFactoryPostProcessor甚至可以修改bean实例本身,因它可调到getBean方法!
@Configuration注解处理
特别的,@Configuration注解也是在bean的后处理这个阶段进行的,用的是ConfigurationClassPostProcessor这个bean,它实现了BeanDefinitionRegistryPostProcessor接口。而且,由于它同时实现了PriorityOrdered接口,所以它是第一个被执行的BeanDefinitionRegistryPostProcessor。
ConfigurationClassPostProcessor处理完@Configuration注解后,会刷新相应的配置bean定义,等到finishBeanFactoryInitialization()里再统一实例化。
所以,@Configuration注解的处理在invokeBeanFactoryPostProcessors里,而其实例化则在finishBeanFactoryInitialization()里,更具体的是在DefaultListableBeanFactory.preInstantiateSingletons()里。