- 前言
- springboot的启动流程
- 钩子接口的扩展机制
- springboot的自动装配机制
- 自定义starter
前言
整理下以前分析过的springboot源码笔记,遗忘了方便查阅。springboot2.1.3版本。
springboot的启动流程
springboot启动类被@SpringBootApplication注解,该注解是个复合注解,注解的层次如下
@SpringBootApplication
|-@SpringBootConfiguration
|-@Configuration //说明启动类是个配置类
|-@Component //说明启动类是个bean
|-@EnableAutoConfiguration
|-@AutoConfigurationPackage
|-@Import(AutoConfigurationPackages.Registrar.class)
|-@Import(AutoConfigurationImportSelector.class) //
|-@ComponentScan //说明会扫描启动类所在包以及其子包下的被@Component注解的类为bean对象
先贴流程图图
说下springboot大体启动流程:
Step1:创建SpringApplication对象
Step2:加载spring.factories文件内的ApplicationContextInitializer并实例化保存到属性SpringApplication.initializers集合
Step3:加载spring.factories文件内的ApplicationListener并实例化保存到属性SpringApplication.listeners集合
Step4:从该步骤开始进入run方法,加载META-INF/spring.factories文件内的SpringApplicationRunListener并实例化(默认是EventPublishingRunListener)保存到局部变量SpringApplicationRunListeners属性listeners集合
Step5:执行SpringApplicationRunListener的starting动作,触发spring.factories内的监听器ApplicatonListener
Step6:执行SpringApplicationRunListener的environmentPrepared动作,触发spring.factories内的监听器ApplicatonListener
Step7:创建ApplicationContext,springboot启动引入了web模块默认是AnnotationConfigServletWebServerApplicationContext
Step8:加载spring.factories文件内的SpringBootExceptionReporter并实例化,默认FailureAnalyzers,在springboot启动异常时候报告异常,这个通常不需要关注
Step9:执行spring.factories文件内的ApplicationContextInitializer
Step10:执行SpringApplicationRunListener的contextPrepared动作,触发spring.factories内的监听器ApplicatonListener
Step11:把springboot启动类注册为bean
Step12:执行SpringApplicationRunListener的contextLoaded动作,触发spring.factories内的监听器ApplicatonListener
Step13:IOC容器刷新,这个是spring的启动核心方法,这里只是spring内容,主要功能是扫描注解,把单例都注册为bean
Step14:添加JVM钩子方法,用于kill $PID关闭springboot容器
Step15:执行SpringApplication的afterRefresh方法,这个是protected空方法,供开发者实现,在IOC容器刷新后做一些处理。
Step16:执行SpringApplicationRunListener的started动作,触发spring.factories内的监听器ApplicatonListener
Step17:执行IOC容器中bean类型为ApplicationRunner、CommandLineRunner的run方法
Step18:执行SpringApplicationRunListener的running动作,触发spring.factories内的监听器ApplicatonListener
至此springboot启动完成
从流程图可知,springboot的启动本质就是IOC容器的启动,只是通过监听器扩展了功能,在springboot容器的不同阶段,执行对应的监听器执行功能而已。下面就分析IOC容器的启动
refresh()源码解释
spring boot启动,IOC的refresh()方法是在
AnnotationConfigServletWebServerApplicationContext.refresh()
即org.springframework.context.support.AbstractApplicationContext.refresh()内
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();//@1
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();//@2
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);//@3
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);//@4
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);//@5
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);//@6
// Initialize message source for this context.
initMessageSource();//@7
// Initialize event multicaster for this context.
initApplicationEventMulticaster();//@8
// Initialize other special beans in specific context subclasses.
onRefresh();//@9
// Check for listener beans and register them.
registerListeners();//@10
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);//@11
// Last step: publish corresponding event.
finishRefresh();//@12
}
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();//@13
}
}
}
@1:context刷新前的准备工作,比如初始化placeholder属性配置,验证properties文件的合法性
@2:创建BeanFactory对象,即DefaultListableBeanFactory对象
@3:准备在此上下文中使用的bean工厂。即为DefaultListableBeanFactory对象的属性设置值,比如设置classloader,设置BeanPostProcessor、设置ignoredDependencyInterfaces、向beanFactory注册一些系统bean等工作。
@4:允许在上下文子类中对bean工厂进行后处理。注册WebApplicationContextServletContextAwareProcessor这个BeanPostProcessor到bean工厂。为什么要单独注册这个呢?原因是什么?
@5:调用在上下文中注册为bean的工厂处理器。该方法是spring的核心方法,核心扩展机制。即把BeanFactoryPostProcessor类型的bean实例化注册到applicationContext
@6:把类型是BeanPostProcessor的bean实例化并缓存到DefaultListableBeanFactory.beanPostProcessors集合,用于后面普通bean实例化的时候对bean进行修改。
@7:初始化MessageSource,用于国际化。
@8:初始化广播SimpleApplicationEventMulticaster,后续用于spring事件机制
@9:protected方法,用于扩展,对于引入了spring-web来说,那么这个钩子方法是用于启动tomcat
@10:1.获取spring初始化时候,缓存到AbstractApplicationContext.applicationListeners的监听器;2.获取类型ApplicationListener注册到BeanFactory的bean;把以上2中情况的监听器都缓存到SimpleApplicationEventMulticaster.defaultRetriever.applicationListeners集合,这样spring对bean实例化完毕后,就会执行监听器,做一些收尾工作。
@11: 把注册到BeanFactory的bean实例化并缓存到DefaultListableBeanFactory.singletonObjects,这里的finishBeanFactoryInitialization是个protected方法,我们开发可以自己继承实现。此外该方法也会冻结已经注册的bean,这样单例bean数量不会再变化。
@12:最后一步刷新,主要功能就是执行spring的监听器。事件机制也是spring的一大扩展点。我们的bean可以实现ApplicationListener接口,在bean实例化后做一些后续工作。
invokeBeanFactoryPostProcessors源码分析
这里的源码是refresh()的代码@5
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
return this.beanFactoryPostProcessors;//@1
}
@1:返回IOC容器对象applicationContext注册的BeanFactoryPostProcessor集合,这些集合的元素是什么时候添加的呢?是在监听器、初始化时候添加的,具体可以debug,默认引入springboot-web时候该集合内容是[CachingMetadataReaderFactoryPostProcessor、ConfigurationWarningsPostProcessor、PropertySourceOrderingPostProcessor]
接着看invokeBeanFactoryPostProcessors方法
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<>();//保存处理过的bean
if (beanFactory instanceof BeanDefinitionRegistry) {//传入的beanFactory是DefaultListableBeanFactory
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();//保存实现了BeanFactoryPostProcessor但是未实现BeanDefinitionRegistryPostProcessor的bean
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();//保存实现了BeanDefinitionRegistryPostProcessor的bean
//代码@0-begin
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {//遍历参数beanFactoryPostProcessors中是BeanDefinitionRegistryPostProcessor类型的bean
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
/*
* 比如执行的是CachingMetadataReaderFactoryPostProcessor、ConfigurationWarningsPostProcessor的postProcessBeanDefinitionRegistry方法
*/
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
//代码@0-end
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// Separate between BeanDefinitionRegistryPostProcessors that implement
// PriorityOrdered, Ordered, and the rest.
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
/*
* 代码@1-begin -> @1-end 功能是 获取注册到beanFactory的BeanDefinition,获取到的结果有[org.springframework.context.annotation.internalConfigurationAnnotationProcessor]
* 对应的bean是ConfigurationClassPostProcessor,这个bean是注解方式启动的核心bean,如果该bean实现了PriorityOrdered,则执行其postProcessBeanDefinitionRegistry方法
*/
//代码@1-begin
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {//ppName对应的bean实现了PriorityOrdered接口
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);//代码@1.1,这里主要是去执行ConfigurationClassPostProcessor,该类会去加载bean,处理@Import、@Compoment、@Configuration
currentRegistryProcessors.clear();
//代码@1-end
// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
/*
* @2-begin -> @2-end 功能是 获取注册到beanFactory的BeanDefinition,获取到的结果有[org.springframework.context.annotation.internalConfigurationAnnotationProcessor]
* 对应的bean是ConfigurationClassPostProcessor,这个bean是注解方式启动的核心bean,如果该bean实现了Ordered,则执行其postProcessBeanDefinitionRegistry方法
*/
//代码@2-begin
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {//ppName对应的bean实现了Ordered接口
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
//代码@2-end
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
/*
* @3-begin -> @3-end功能是获取注册到beanFactory的类型是BeanDefinitionRegistryPostProcessor的BeanDefinition,实例化未实现PriorityOrdered、Ordered接口的bean,
* 执行其postProcessBeanDefinitionRegistry方法
*/
//代码@3-begin
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));//实例化
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);//代码@3.1,执行postProcessBeanDefinitionRegistry方法
currentRegistryProcessors.clear();
}
//代码@3-end
// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);//代码@4, 此处执行@1、@2、@3处实现了BeanDefinitionRegistryPostProcessor的bean的postProcessBeanFactory方法
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);//代码@5,此处执行只实现了BeanFactoryPostProcessor的bean的postProcessBeanFactory方法
}
else {//忽略
// Invoke factory processors registered with the context instance.
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);//获取实现了BeanFactoryPostProcessor接口的bean
// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
//代码@6-begin
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();//保存实现了BeanFactoryPostProcessor和PriorityOrdered的bean
List<String> orderedPostProcessorNames = new ArrayList<>();//保存实现了BeanFactoryPostProcessor和Ordered的bean名称
List<String> nonOrderedPostProcessorNames = new ArrayList<>();//保存实现了BeanFactoryPostProcessor但不实现PriorityOrdered、Ordered的bean名称
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {//跳过实现了BeanDefinitionRegistryPostProcessor的bean
// skip - already processed in first phase above
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {//如果bean实现了BeanFactoryPostProcessor和PriorityOrdered
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));//实例化bean
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {//如果bean实现了BeanFactoryPostProcessor和Ordered
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);//执行postProcessBeanFactory方法,这里是PropertySourcesPlaceholderConfigurer,该bean工厂后置处理器是用于处理@value等
//代码@6-end
// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
//代码@7-begin
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));//实例化实现了BeanFactoryPostProcessor和Ordered接口的bean
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
//代码@7-end
// Finally, invoke all other BeanFactoryPostProcessors.
//代码@8-begin
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));//实例化实现了BeanFactoryPostProcessor但不实现PriorityOrdered、Ordered接口的bean
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
//代码@8-end
// Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values...
beanFactory.clearMetadataCache();
}
代码@0处:遍历传入的参数beanFactoryPostProcessors,执行类型是BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法
代码@1处:获取类型是BeanDefinitionRegistryPostProcessor的bean,如果实现了PriorityOrdered接口,则实例化bean,并执行bean的postProcessBeanDefinitionRegistry方法。这里重要的就是ConfigurationClassPostProcessor,该类会向BeanDefination集合加入配置类引入的XxxBeanFactoryPostProcessor
代码@1.1处,主要是去执行ConfigurationClassPostProcessor,该类会去加载bean,处理@Import、@Compoment、@Configuration,这个是关键
代码@2处:获取类型是BeanDefinitionRegistryPostProcessor的bean,如果实现了Ordered接口,则实例化bean,并执行bean的postProcessBeanDefinitionRegistry方法
代码@3处:获取类型是BeanDefinitionRegistryPostProcessor但是不实现Ordered\PriorityOrdered接口的bean,实例化bean,并执行bean的postProcessBeanDefinitionRegistry方法。比如执行dubbo的ServiceAnnotationBeanPostProcessor,处理dubbo @Service
代码@4处:执行@1、@2、@3处实现了BeanDefinitionRegistryPostProcessor的bean的postProcessBeanFactory方法
代码@5处:执行参数beanFactoryPostProcessors中只实现了BeanFactoryPostProcessor的bean的postProcessBeanFactory方法
代码@6处:获取类型是BeanFactoryPostProcessor的bean,如果实现了PriorityOrdered接口,则实例化bean,并执行bean的postProcessBeanFactory方法
代码@7处:获取类型是BeanFactoryPostProcessor的bean,如果实现了Ordered接口,则实例化bean,并执行bean的postProcessBeanFactory方法
代码@8处:获取类型是BeanFactoryPostProcessor的bean,实例化bean,并执行bean的postProcessBeanFactory方法
通过上面8种情况,就把实现了BeanDefinitionRegistryPostProcessor或BeanFactoryPostProcessor的所有bean都进行了处理。
综上:代码@1、@2、@3是处理类型是BeanDefinitionRegistryPostProcessor的bean,代码@4、@5、@6是处理BeanFactoryPostProcessor的bean,BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子接口,关系如图
BeanFactoryPostProcessor是BeanFactory的后置处理器,是针对于beanFactory的扩展点,即spring会在beanFactory初始化之后,beanDefinition都已经loaded,但是bean还未创建前进行调用,可以修改,增加beanDefinition。通常扩展实现BeanFactoryPostProcessor即可,如果想在bean的加载前进行用户自定义功能,实现BeanDefinitionRegistryPostProcessor。如果要求有优先顺序,则需要实现PriorityOrdered或Ordered接口。
重点说下:
代码@1.1处:这里是执行的是ConfigurationClassPostProcessor,那么该bean是什么时候加载到BeanFactory的呢?是在org.springframework.boot.SpringApplication.createApplicationContext()这里地方,通过反射生成ConfigurableApplicationContext对象的时候,比如引入了springboot web模块,创建的是AnnotationConfigServletWebServerApplicationContext,该类实例化的时候如下:
public AnnotationConfigServletWebServerApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);//执行org.springframework.context.annotation.AnnotationConfigUtils.registerAnnotationConfigProcessors(BeanDefinitionRegistry, Object),注册spring内部bean,org.springframework.context.annotation.internalConfigurationAnnotationProcessor->ConfigurationClassPostProcessor
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
会自动注册内部bean ConfigurationClassPostProcessor,该类是注解启动的关键,处理@Configuration、@Compoment、@Import,该类功能后续再讲解。
代码@6处主要是执行PropertySourcesPlaceholderConfigurer,这个是属性处理,处理@Value
下面来看ConfigurationClassPostProcessor的功能,这个类是spring最核心最复杂的方法,自动装配就是该类实现的
ConfigurationClassPostProcessor源码分析
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);
processConfigBeanDefinitions(registry);
}
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();//获取已经注册的bean名称集合,此时注册的bean除了spring内部bean就是用户启动的配置类,用户启动的配置类是在SpringApplication.prepareContext(ConfigurableApplicationContext, ConfigurableEnvironment, SpringApplicationRunListeners, ApplicationArguments, Banner)阶段的SpringApplication.load(ApplicationContext, Object[])注册用户启动的配置类为bean的
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) || //beanDef的属性上org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass值为full
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {//beanDef的属性上org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass值为lite
//通常beanDef的属性上org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass值为null,因此不进入该分支
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {//类上被@Configuration @Component、@ComponentScan、@Import、@ImportResource注解,或者方法上被@Bean注解
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// Return immediately if no @Configuration classes were found
if (configCandidates.isEmpty()) {//springboot注解方式启动,configCandidates默认是启动的配置类,通常只有一个
return;
}
// Sort by previously determined @Order value, if applicable
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// Detect any custom bean name generation strategy supplied through the enclosing application context
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);//generator是在SpringApplication.prepareContext(ConfigurableApplicationContext, ConfigurableEnvironment, SpringApplicationRunListeners, ApplicationArguments, Banner)阶段的SpringApplication.postProcessApplicationContext(ConfigurableApplicationContext)注册的
if (generator != null) {//false,存在generator
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);//创建配置类解析对象,比如dubbo解析@com.alibaba.dubbo.config.annotation.Service也是使用该类进行解析
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);//常规springboot方式启动,configCandidates内只有一个元素,即配置类
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
parser.parse(candidates);//@@1//核心方法,解析配置类
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());//获取解析配置类得到的@Import引入的类、@ImportResource引入的资源文件、@Bean注解的方法 集合
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
this.reader.loadBeanDefinitions(configClasses);//@@2 //把@Import引入的类、@ImportResource引入的资源文件、@Bean注解的方法生成的对象 注册为bean
alreadyParsed.addAll(configClasses);
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {//注册的bean数量有变化
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));//把没有解析过的配置类保存到candidates,用于循环解析和注册过程
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());//如果解析配置类后,bean数量有变化,则candidates是非空,因此再继续循环执行解析配置类和注册bean过程,这样不断循环,直到candidates为空退出,这样就解决了配置类上还有配置类的情况
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
processConfigBeanDefinitions方法的核心是代码@@1和@@2处,代码@@1负责解析配置类,代码@@2负责把解析到的类注册为bean,下面先看@@1这个方法
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {//注解方式启动执行该分支
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());//@1
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
//解析配置类后,存在@Import引入DeferredImportSelector类型,比如springboot的自动装配AutoConfigurationImportSelector就是DeferredImportSelector
this.deferredImportSelectorHandler.process();//@2 springboot自动装配的具体实现
}
配置类是注解,那么对应的BeanDefinition就是AnnotatedBeanDefinition,因此执行代码@1。代码@2处是处理@Import引入类是DeferredImportSelector类型,该类的解析后续再说。
接着看代码@1处
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {//配置类不被@Conditional注解
return;
}
//配置类被@Conditional注解
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {//配置类如果已经被处理过了
if (configClass.isImported()) {//配置类是被@Import引入的,避免重复处理,则不再解析
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
// Otherwise ignore new imported config class; existing non-imported class overrides it.
return;
}
else {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
// Recursively process the configuration class and its superclass hierarchy.
SourceClass sourceClass = asSourceClass(configClass);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass);//@@3 //解析配置类,核心方法
}
while (sourceClass != null);//为null时候退出
this.configurationClasses.put(configClass, configClass);//处理过的@Configuration、@Component、@bean、@Import引入的类都缓存到ConfigurationClassParser.configurationClasses集合上,后续获取该集合,从而注册为bean
}
processConfigurationClass方法的核心逻辑判断处理配置类,并把每个处理过的配置类(包括普通bean)都缓存到ConfigurationClassParser.configurationClasses集合
ConfigurationClassParser的debug图如下
类结构图如下
总之就是ConfigurationClassParser.configurationClasses集合缓存的是bean(@Componet扫描的bean、配置bean、@Import(ImportSelect类型)引入注册的bean)包装对象ConfigurationClasses,而每个ConfigurationClasses对象上又保存了@Bean、@Import(AutoConfigurationPackages.Registrar类型)引入。其中特殊的是@Import(DeferredImportSelector类型)是保存在ConfigurationClassParser.deferredImportSelectorHandler集合上,这个主要是springboot内部自动装配的实现。
processConfigurationClass处理流程图
接着看doProcessConfigurationClass方法
@Nullable
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {//类是被@Component注解
// Recursively process any member (nested) classes first
//如果配置类被@Component注解,则处理该类上的内部类是配置类的情况,即把内部类处理后并缓存到ConfigurationClassParser.configurationClasses集合
processMemberClasses(configClass, sourceClass);//处理内部类上的@PropertySource、@ComponentScan、@Import、@ImportResource、@Bean注解情况,递归执行doProcessConfigurationClass
}
// Process any @PropertySource annotations
//处理@PropertySources、PropertySource情况,没用过,暂时不清楚用途
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {//配置类被@PropertySource注解,没遇到过,忽略
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
// Process any @ComponentScan annotations
/*
* 处理@ComponentScan注解,@SpringBootApplication是被@ComponentScan注解,默认是扫描启动类所在包下的类,如果被@Component注解,则注册为bean。
* 接着递归执行parse方法,判断这些用户自定义的bean上是否有被@Configuration注解 @Import @bean注解,这样就能把所有的用户自定义的bean上的注解都扫描完。
*/
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
//扫描指定package下的被@Component注解的类注册为bean,除此外,如果用户自定义了includeFilter,则也会扫描自定义的注解为bean
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());//扫描类解析为BeanDefinitionHolder,dubbo扫描@Service也是参考这个做的
// Check the set of scanned definitions for any further config classes and parse recursively if needed
//遍历扫描package注册的bean,把这些bean也进行解析,看看这些用户自定义bean上是否存在@Configuration,就是递归解析@Configuration
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
// 类上被@Configuration @Component、@ComponentScan、@Import、@ImportResource注解,或者方法上被@Bean注解则递归调用parse
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// Process any @Import annotations
/*
* getImports是采用递归方式获取sourceClass上的@Import注解的value
* processImports把@Import注解的value保存到this.configurationClasses集合,供后续把@Import注解的value值集合都注册为bean
*/
processImports(configClass, sourceClass, getImports(sourceClass), true);
// Process any @ImportResource annotations
/*
* 处理@ImportResource注解,这个是为了兼容老应用是xml配置方式,目前已经过时很少使用了,不需要进行深究了
* 只需要知道ImportResource导入的资源也被保存到ConfigurationClass.importedResources,后面也会被注册为bean
*/
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
// Process individual @Bean methods
/*
* 处理方法被@Bean注解,把生成的对象缓存到this.configurationClasses集合,后续会被注册为bean
*/
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
/*
* 如果接口内的非抽象方法被@Bean注解,则把方法缓存到ConfigurationClass.beanMethods
*/
processInterfaces(configClass, sourceClass);
// Process superclass, if any
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}
// No superclass -> processing is complete
return null;
}
doProcessConfigurationClass功能逻辑如下:
接着看processImports
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {//是ImportSelector的实现
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);//实例化
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader, this.registry);//实现了Aware感知接口的处理
if (selector instanceof DeferredImportSelector) {//是DeferredImportSelector的实现
this.deferredImportSelectorHandler.handle(
configClass, (DeferredImportSelector) selector);//缓存到ConfigurationClassParser.DeferredImportSelectorHandler.deferredImportSelectors集合
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);//@Import引入的是ImportSelector的实现,则递归调用processImports处理其上的@Import注解
}
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {//是ImportBeanDefinitionRegistrar的实现
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(
registrar, this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());//缓存到ConfigurationClass.importBeanDefinitionRegistrars集合
}
else {//@Import引入的非ImportSelector、ImportBeanDefinitionRegistrar实现,即一个普通java类,则递归处理其上面的@PropertySource、@ComponentScan、@Import、@ImportResource、@Bean,同时把该类缓存到ConfigurationClassParser.configurationClasses,后续被注册为bean
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
//spring.factories内的自动配置都是直接执行这里,通常是不执行上面两个分支
processConfigurationClass(candidate.asConfigClass(configClass));//@Import引入的对象递归去执行processConfigurationClass,这样就把@Import引入的对象也会缓存到ConfigurationClassParser.configurationClasses,后续被注册为bean。 或者是 处理spring.factories内的自动配置类
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
finally {
this.importStack.pop();
}
}
}
processImports方法主要功能是处理@Import注解,逻辑如下:
1.如果@Import引入的是DeferredImportSelector的实现,则缓存到ConfigurationClassParser.DeferredImportSelectorHandler.deferredImportSelectors集合
2.如果@Import引入的是ImportSelector的实现,则递归处理引入值上的@Import,直至没有@Import执行第4步
3.如果@Import引入的是ImportBeanDefinitionRegistrar,则缓存到ConfigurationClass.importBeanDefinitionRegistrars集合
4.如果@Import引入的是个普通类(包括配置类),没有实现DeferredImportSelector、ImportSelector、ImportBeanDefinitionRegistrar,则递归processConfigurationClass处理该普通类上的注解,并缓存普通类到ConfigurationClassParser.configurationClasses,后续该普通类被注册为bean。
由此可见,@Import引入是有ImportSelector实现(包括DeferredImportSelector实现)、ImportBeanDefinitionRegistrar实现,配置类、普通类,该注解的引入最终都会被注册为bean。
DeferredImportSelector vs ImportSelector区别?
DeferredImportSelector 是ImportSelector的子接口,DeferredImportSelector 会在所有的@Configuration类加载完成之后再加载返回的配置类,同时DeferredImportSelector 的加载顺序可以通过@Order或者实现了Ordered接口来指定,同时DeferredImportSelector 提供了新方法getImportGroup()来跨DeferredImportSelector 实现自定义的Configutaion的加载顺序。
ImportSelector是在加载完@Configuration类之前,先去加载返回的配置类。
对于开发扩展来说,ImportSelector简单,直接实现ImportSelector即可,通常不需要使用DeferredImportSelector(太复杂,是springboot自动装配的实现)
接着回头看org.springframework.context.annotation.ConfigurationClassParser.parse(Set<BeanDefinitionHolder>)方法,该方法执行this.deferredImportSelectorHandler.process();是springboot自动装配的具体实现,处代码如下:
public void process() {
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
try {
if (deferredImports != null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
deferredImports.forEach(handler::register);//@1 执行DeferredImportSelectorGroupingHandler#register
handler.processGroupImports();//@2
}
}
finally {
this.deferredImportSelectors = new ArrayList<>();
}
}
代码@1:比如springboot,执行AutoConfigurationImportSelector#getImportGroup()获取AutoConfigurationGroup实例对象,并缓存到DeferredImportSelectorGroupingHandler.groupings,供代码@2处处理
代码@2:这个是自动装配的关键,即遍历@1处生成的groupings集合,加载META-INF/spring-autoconfigure-metadata.properties文件,该文件是OnCondition的方式确定哪些配置类要被加载(装配),该方法逻辑复杂,自己有些细节也没看明白,DeferredImportSelector接口是spring5比spring4多了实现,spring4的比较简单,见如下代码:
//spring4.3.2的处理DeferredImportSelector
private void processDeferredImportSelectors() {
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR);
for (DeferredImportSelectorHolder deferredImport : deferredImports) {
ConfigurationClass configClass = deferredImport.getConfigurationClass();
try {
String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());//执行selectImports获取引入类
processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
}
}
public interface DeferredImportSelector extends ImportSelector {//spring4 DeferredImportSelector接口无具体实现
}
spring4就是执行selectImports获取获取引入类,处理引入类上的@Import注解,spring5对DeferredImportSelector接口增加了getImportGroup方法,增加这个方法的原因应该是随着装配类的增加,需要用group的方式进行集体装配。
接着回头查看processConfigBeanDefinitions这个顶层方法,该方法太复杂了,以至于看着后面前面的就有些遗忘了,该方法的功能流程如下:
ConfigurationClassPostProcessor.postProcessBeanFactory(ConfigurableListableBeanFactory)功能很复杂,我们只需要知道它在spring的注解启动过程中做了哪些功能,这样才方便我们对spring进行扩展和定制,功能总结如下:
1.根据配置类扫描包下的类,类被@Component注解,则注册为bean。如果自定义了includeFilter,则也会扫描注册为bean。
2.扫描到的类上有@Import注解,则把引入的类(ImportSelector类型)注册为bean,@Import的功能很强大,该注解也就是在该方法内被解析的。
3.把@Bean注解方法的返回结果注册为bean。
4.把@ImportResource引入的资源注册为bean。比如引入的是xml配置的
总之,该方法就是扫描,把扫描结果和引入结果并注册bean。
BeanFactoryPostProcessor的扩展
通过前面1.2、1.3的分析,知道了PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory, List<BeanFactoryPostProcessor>)和ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(BeanDefinitionRegistry)的功能,那么我们写的BeanFactoryPostProcessor实现是如何被加载的呢?实际只需要在我们写的MyBeanFactoryPostProcessor实现上加上@Component,那么在ConfigurationClassPostProcessor.postProcessBeanFactory(ConfigurableListableBeanFactory)自然就会把我们自定义的MyBeanFactoryPostProcessor给注册为bean,接着在invokeBeanFactoryPostProcessors内会执行。
BeanFactoryPostProcessor是针对BeanFactory的扩展,作用就是在bean实例化前,注册一些bean,或者为一些特定的bean修改其属性等。后面spring实例化bean的时候还有个BeanPostProcessor,这个是对bean的扩展,用于在bean的初始化前后、实例化前后对bean进行修改,比如动态代理。
registerBeanPostProcessors源码分析,BeanPostProcessor
这里的源码是refresh()的代码@6
该方便和invokeBeanFactoryPostProcessors套路基本相同,首先也是获取已经注册的是BeanPostProcessor类型的bean,然后按照优先级顺序实例化BeanPostProcessor类型的bean,然后把这些BeanPostProcessor类型的bean缓存到BeanFactory,即缓存到DefaultListableBeanFactory.beanPostProcessors,即AbstractBeanFactory.beanPostProcessors集合,这样在后续普通bean实例化的时候,BeanPostProcessor就可以对bean进行修改了。
BeanFactoryPostProcessor vs BeanPostProcessor
BeanFactoryPostProcessor是对BeanFactory的扩展,在用户bean的实例化前对BeanFactory做一些前置处理,比如增加一些特定的内部bean,还有就是扫描,比如dubbo的扫描@Service,通常第三方框架要和spring整合一起,要使用到BeanFactoryPostProcessor,因为它的功能更加靠前。
BeanPostProcessor是对bean的扩展,对bean进行配置和修改,比如AOP功能就是使用的BeanPostProcessor在bean初始化完毕后,对bean生成动态代理类。
registerListeners源码分析
这里的源码是refresh()的代码@10
/**
* Add beans that implement ApplicationListener as listeners.
* Doesn't affect other listeners, which can be added without being beans.
*/
protected void registerListeners() {
// Register statically specified listeners first.
for (ApplicationListener<?> listener : getApplicationListeners()) {//@1
getApplicationEventMulticaster().addApplicationListener(listener);//@2
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {//@3
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);//@4
}
// Publish early application events now that we finally have a multicaster...
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
代码@1:遍历ApplicationContext创建后注册到其上面的监听器ApplicationListener,即AbstractApplicationContext.applicationListeners,把这些监听器缓存到SimpleApplicationEventMulticaster.defaultRetriever.applicationListeners集合上,而SimpleApplicationEventMulticaster又是保存在AbstractApplicationContext.applicationEventMulticaster属性上,这样用于后面bean实例化完毕后执行事件机制,即执行监听器方法onApplicationEvent。
那么问题来了:AbstractApplicationContext.applicationListeners的监听器是什么时候保存的呢?是在springboot的run方法内把spring.factories文件内的org.springframework.context.ApplicationListener对应的类对象保存的。具体保存的堆栈:
SpringApplication.run(String...)
SpringApplication.prepareContext(ConfigurableApplicationContext, ConfigurableEnvironment, SpringApplicationRunListeners, ApplicationArguments, Banner)
SpringApplicationRunListeners.contextLoaded(ConfigurableApplicationContext)
EventPublishingRunListener.contextLoaded(ConfigurableApplicationContext)//把spring.factories文件内的org.springframework.context.ApplicationListener对应的类对象缓存到AbstractApplicationContext.applicationListeners集合
注意这些监听器并不是bean,因为没有注册到BeanFactory
代码@2:把spring.factories文件内的监听器缓存到SimpleApplicationEventMulticaster.defaultRetriever.applicationListeners集合上
代码@3:获取已经注册的类型是ApplicationListener的bean名称,此时这些监听器bean还未被实例
代码@4:把代码@3处的类型是监听器bean名称缓存到SimpleApplicationEventMulticaster.defaultRetriever.applicationListenerBeans集合上。这些未实例化的监听器bean,在实例化后被ApplicationListenerDetector这个BeanPostProcessor后置处理器处理添加到SimpleApplicationEventMulticaster.defaultRetriever.applicationListeners集合上,在finishRefresh()内的publishEvent方法进行广播的时候,执行对应的监听事件。
这里就涉及到AbstractApplicationContext和SimpleApplicationEventMulticaster之间的关系了,关系如图所示:
从图上很清楚可以看出类之间的关闭,java语音是封装、继承、多态,这里类之间的关系就是封装。
从接口层面说:ApplicationContext保存了事件广播器ApplicationEventMulticaster。
这里ApplicationContext就是个事件源
事件是ApplicationEvent,包装了ApplicationContext。
监听器是ApplicationListener
ApplicationEventMulticaster实际就是个监听器的集合
事件源ApplicationContext有变化,就包装为事件ApplicationEvent给监听器,监听器ApplicationListener执行对应的动作。
事件机制的写法通常就是:事件源有个属性是监听器集合,事件源状态有变化,把事件源包装为事件,然后遍历监听器集合,每个监听器执行动作。tomcat的LifecycleBase、LifecycleListener、LifecycleEvent是这样,spring的事件机制也是如此。
ApplicationListener定义如下
ApplicationListener
如果自定义了监听器和事件,需要进行广播,那么service bean内直接注入个ApplicationEventPublisher即可,ApplicationEventPublisher是ApplicationContext的父接口,实际就是执行的AbstractApplicationContext.publishEvent(Object),注入是在ApplicationContextAwareProcessor.postProcessBeforeInitialization(Object, String)内注入的
finishBeanFactoryInitialization方法的preInstantiateSingletons源码解析
这里的源码是refresh()的代码@11
这里是bean创建流程,先看bean的创建流程图
bean的创建总体分为,bean实例化,bean传播注入,bean初始化,每个步骤都会经过BeanPostProcessor集合的前后置处理。知道了这个流程,就知道如何对bean进行扩展了。
遍历BeanPostProcessor集合基本都是在AbstractAutowireCapableBeanFactory类的applyXXX()方法内进行遍历对bean进行处理。
BeanPostProcessor类型的处理,几个重要点
ApplicationContextAwareProcessor 是初始化前,如果bean是aware接口,则设置aware属性
ApplicationListenerDetector ,如果bean是监听器,则把实例化后的bean缓存到AbstractApplicationContext.applicationListeners
SmartInitializingSingleton说明
在preInstantiateSingletons()内如果已经注册的bean都已经创建完毕,那么遍历所有的bean,如果bean是SmartInitializingSingleton类型,则执行钩子方法afterSingletonsInstantiated(),是在所有单例bean(非懒加载对象)都已经被创建后执行,跟InitializingBean有点像。那么SmartInitializingSingleton的实际例子有什么呢?真想不出bean都实例化后,还进行收尾工作的需求是什么。spring有个EventListenerMethodProcessor内部bean,实现了SmartInitializingSingleton,该类在所有单例bean(非懒加载对象)都已经被创建后,查找被@EventListener注解的方法,把这个方法创建一个监听器ApplicationListenerMethodAdapter,加到ApplicationContext的监听器上,这样就可以通过注解方式来进行使用spring监听器了。但是实际上生成的ApplicationListenerMethodAdapter对象并不会被作为bean保存到IOC容器内,只是作为监听器集合的一个元素而已。个人认为@EventListener不如实现ApplicationListener好,有点鸡肋。
rocketmq starter内自动配置RocketMQTransactionConfiguration就实现了SmartInitializingSingleton,用于所有bean都初始化后,获取@RocketMQTransactionListener注解的bean,和spring处理@EventListener方式完全相同。
钩子接口的扩展机制
BeanFactoryPostProcessor
1.BeanFactoryPostProcessor:是针对于beanFactory的扩展点,即spring会在beanFactory初始化之后,beanDefinition都已经loaded,但是bean还未创建前进行调用,可以修改,增加beanDefinition
2.BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子接口:是针对于beanFactory的扩展点,即spring会在调用BeanFactoryPostProcessor之前调用他。
具体使用就是实现BeanFactoryPostProcessor,加上@Component,这样就被加载到了。通常只实现BeanFactoryPostProcessor即可
BeanPostProcessor
1.BeanPostProcessor:是针对bean的扩展点,即spring会在bean初始化前后 调用方法对bean进行处理
2.InstantiationAwareBeanPostProcessor是BeanPostProcessor的子接口:是针对于bean的扩展点,即spring会在bean实例化前后进行调用
3.SmartInstantiationAwareBeanPostProcessor是InstantiationAwareBeanPostProcessor的子接口:是针对于bean的扩展点,预测已处理bean的最终类型,或者觉得bean实例化需要的构造函数,或者获取早期的bean
4.MergedBeanDefinitionPostProcessor是BeanPostProcessor的子接口:是针对于bean的扩展点,即spring会处理某个给定的beanDefinition于原本的bean进行merged
具体使用就是实现BeanPostProcessor,加上@Component,这样就被加载到了。通常只实现BeanPostProcessor即可
Aware
感知接口Aware
BeanNameAware,实现了这个接口的bean,可以获取beanName
BeanClassLoaderAware,实现了这个接口的bean,可以获取beanClassLoader
BeanFactoryAware,实现了这个接口的bean,可以获取BeanFactory
以上三个Aware接口是在bean实例化后进行注入。
下面这些Aware接口是在ApplicationContextAwareProcessor 这个BeanPostProcessor的bean初始化前置阶段注入
EnvironmentAware,实现了这个接口的bean,可以获取Environment
EmbeddedValueResolverAware,实现了这个接口的bean,可以获取StringValueResolver
ResourceLoaderAware,实现了这个接口的bean,可以获取ResourceLoader
ApplicationEventPublisherAware,实现了这个接口的bean,可以获取ApplicationEventPublisher,用于广播,而ApplicationEventPublisher是 ApplicationContext的父接口,因此实际获取的就是ApplicationContext
MessageSourceAware,实现了这个接口的bean,可以获取MessageSource
ApplicationContextAware,实现了这个接口的bean,可以获取ApplicationContext
InitializingBean、DisposableBean
如果bean实现了InitializingBean接口,则在bean的初始化阶段执行afterPropertiesSet(),对bean进行初始化,比如该bean作为一个SocketServer,则可以在afterPropertiesSet()内启动服务监听端口。
如果bean实现了DisposableBean接口,那么在spring容器关闭的时候,会执行destroy()销毁bean,比如bean启动了端口监听服务,那么可以在destroy()内关闭监听端口。
事件机制
spring事件机制
spring的事件机制涉及到事件源EventSource、事件EventObject、监听器Listener,事件是ApplicationEvent、监听器是ApplicatonListener,事件源通常就是ApplicaitonContext。
事件源ApplicaitonContext持有监听器集合(即广播对象ApplicationEventMulticaster ,持有监听器集合),ApplicaitonContext状态发生变化,则触发监听器执行,监听器只执行对应类型的ApplicationEvent。
几个重要的ApplicationEvent子类
ContextRefreshedEvent,在IOC容器finishRefresh()完成刷新阶段触发
事件机制在实际应用过程的作用:
通过Spring事件机制完成服务启动后的信息整理(类似于Dubbo的服务暴露机制)
通过Spring事件机制获取HTTP请求调用详情
开发者实现ApplicatonListener自定义监听器,实现ApplicationEvent自定义事件,如果需要广播,则可以通过实现ApplicationEventPublisherAware或者直接注入ApplicationEventPublisherAware来进行广播,触发自定义的监听器执行自定义事件
spring boot事件机制
springboot使用的监听器是SpringApplicationRunListener也是事件机制,SpringApplicationRunListener对starting 、environmentPrepared 、environmentPrepared 、contextPrepared 、contextLoaded 、started、running、failed动作做出对应监听
| 动作 | 事件 | 事件源 |
|---|---|---|
| starting | ApplicationStartingEvent | SpringApplication |
| environmentPrepared | ApplicationEnvironmentPreparedEvent | SpringApplication |
| contextPrepared | ApplicationContextInitializedEvent | SpringApplication |
| contextLoaded | ApplicationPreparedEvent | SpringApplication |
| started | ApplicationStartedEvent | SpringApplication |
| running | ApplicationReadyEvent | SpringApplication |
| failed | ApplicationFailedEvent | SpringApplication |
在springboot启动过程中,对于上述动作,都会触发监听器执行,监听器实际还是ApplicationListener,springboot启动创建SpringApplication的时候加载spring.factories内的org.springframework.context.ApplicationListener,加载org.springframework.boot.SpringApplicationRunListener默认是EventPublishingRunListener,EventPublishingRunListener持有事件源SpringApplication,广播(即监听器集合)SimpleApplicationEventMulticaster,在每个动作的时候,都让广播去遍历监听器执行监听动作,和spring的事件机制完全相同。如果我们需要在springboot启动的过程进行监听,则配置到spring.factories的org.springframework.context.ApplicationListener节点即可。springboot使用事件机制启动是真解耦呀,加啥功能,直接加个监听器即可。
springboot开发监听器的几种方式
1.监听器配置在spring.factories,这样springboot启动就会加载监听器,作用于springboot的启动阶段和IOC容器的启动完毕阶段,程序运行阶段。
2.bean直接实现ApplicationListener接口,这样只是作用于IOC容器的启动完毕阶段,程序运行阶段。
3.bean的方法上用@EventListener注解,功能同2。
FactoryBean
FactoryBean是个bean,IOC容器的getBean()方法获取这个类型是&beanName方式获取,常用于创建一类相同的bean,比如mybatis接口生成的bean,就是使用的FactoryBean。具体在mybatis分析的时候分析
BeanFactory是bean工厂,是spring的顶层接口,用于创建bean。
SmartInitializingSingleton
该类是在所有的单例bean(非懒加载)都创建后,如果bean是SmartInitializingSingleton类型,则执行,目前遇到的就是@EventListener的处理使用到了,其它需要上暂时没用到。
ImportBeanDefinitionRegistrar
ImportBeanDefinitionRegistrar的作用是注册bean,通常用于@Import中,那么ImportBeanDefinitionRegistrar和自定义的BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor的执行顺序是什么呢?
通过《invokeBeanFactoryPostProcessors源码分析》的分析:
先执行内部bean ConfigurationClassPostProcessor这个BeanDefinitionRegistryPostProcessor类型,这个类用于扫描和引入注册bean,那么在这个步骤的时候,@Import(ImportBeanDefinitionRegistrar类型)就会被执行,然后是执行自定义的BeanDefinitionRegistryPostProcessor,再执行自定义的BeanFactoryPostProcessor。
总结:
BeanDefinitionRegistryPostProcessor实现类只要加注解(@Component)就可以执行,而ImportBeanDefinitionRegister加注解(@Component)只是交给spring管理,并不会执行接口的方法,必须要在配置类中@Import()才会发挥作用;
ImportBeanDefinitionRegister执行顺序更早
mybatis中@MapperScan 注解就是利用ImportBeanDefinitionRegister
将接口生成代理类然后注册到BeanFactory中,这就是为什么mybatis中只有接口没有实现类的原因
springboot的自动装配机制
自动装配@EnableAutoConfiguration,核心原理是加载spring.factories文件内的org.springframework.boot.autoconfigure.EnableAutoConfiguration,然后根据@Conditional条件确定装配对应的XXXAutoConfiguration,这些XXXAutoConfiguration会被注册为内bean,同时也通过@Bean、@Import创建引入bean,这样就完成了对应功能的装配,具体看下面分析。
自动装配
自动装配源码分析
入口是this.deferredImportSelectorHandler.process(),就是在ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(BeanDefinitionRegistry)这个spring的核心内部BeanFactoryPostProcess调用:
接着看process()方法
//DeferredImportSelectorHandler.process()
public void process() {
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;//保存是就是@Import(DeferredImportSelector类型)的对象集合
this.deferredImportSelectors = null;
try {
if (deferredImports != null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);//排序
deferredImports.forEach(handler::register);//代码@1
handler.processGroupImports();//代码@2
}
}
finally {
this.deferredImportSelectors = new ArrayList<>();//清空
}
}
代码分析:
代码@1:执行DeferredImportSelectorGroupingHandler.register(DeferredImportSelectorHolder),把importGroup缓存到DeferredImportSelectorGroupingHandler.groupings集合,供代码@2处使用
代码@2:遍历DeferredImportSelectorGroupingHandler.groupings集合,获取经过@Conditional过滤后符合自动装配的XXXAutoConfiguration,然后执行processImports操作把XXXAutoConfiguration注册为bean、把XXXAutoConfiguration上的@Import进行导入,这样就把spring.factories内org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的值就进行了自动装配。那么核心功能就是在代码@2处了
//DeferredImportSelectorGroupingHandler.processGroupImports()
public void processGroupImports() {
for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {//代码@3
grouping.getImports().forEach(entry -> {//代码@4
ConfigurationClass configurationClass = this.configurationClasses.get(
entry.getMetadata());//代码@5
try {
processImports(configurationClass, asSourceClass(configurationClass),
asSourceClasses(entry.getImportClassName()), false);//代码@6
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configurationClass.getMetadata().getClassName() + "]", ex);
}
});
}
}
代码@3:遍历是元素默认是一个,DeferredImportSelectorGrouping.group是AutoConfigurationGroup
代码@4:grouping.getImports()返回的是经过spring-autoconfigure-metadata.properties过滤掉的自动配置集合,然后遍历集合,处理XXXAutoConfiguration。
代码@5:通常就是springboot的启动类
代码@6:处理XXXAutoConfiguration,注册XXXAutoConfiguration为bean,把XXXAutoConfiguration方法上的@Bean注册为bean,把XXXAutoConfiguration上的@Import进行注册为bean。
其它地方前面都分析过,但是代码@4处是如何通过spring-autoconfigure-metadata.properties文件过滤掉不符合的自动装配的呢?下面进行分析
//DeferredImportSelectorGrouping.getImports()
public Iterable<Group.Entry> getImports() {
for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {//代码@7
this.group.process(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getImportSelector());//代码@8 这里this.group.process方法传入的参数就是@Import(DeferredImportSelector类型)
}
return this.group.selectImports();//代码@9 返回过滤后的自动装配集合
}
代码@7:this.deferredImports缓存的是@Import(DeferredImportSelector类型)
代码@8:通过spring-autoconfigure-metadata.properties文件过滤spring.factories文件内的自动装配
代码@9:把经过spring-autoconfigure-metadata.properties过滤的自动装配进行排序,排序由@AutoConfigureOrder、@AutoConfigureBefore、@AutoConfigureAfter决定,最终返回经过过滤后返回排序好的自动装配集合。
核心是this.group.process方法,功能就是通过spring-autoconfigure-metadata.properties过滤
//AutoConfigurationGroup.process(AnnotationMetadata, DeferredImportSelector)
public void process(AnnotationMetadata annotationMetadata,
DeferredImportSelector deferredImportSelector) {
Assert.state(
deferredImportSelector instanceof AutoConfigurationImportSelector,
() -> String.format("Only %s implementations are supported, got %s",
AutoConfigurationImportSelector.class.getSimpleName(),
deferredImportSelector.getClass().getName()));
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
.getAutoConfigurationEntry(getAutoConfigurationMetadata(),//getAutoConfigurationMetadata()返回的就是加载了spring-autoconfigure-metadata.properties文件的Properties对象
annotationMetadata);//代码@10
this.autoConfigurationEntries.add(autoConfigurationEntry);//代码@11
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
this.entries.putIfAbsent(importClassName, annotationMetadata);//代码@12
}
}
代码@10:通过spring-autoconfigure-metadata.properties文件过滤spring.factories文件内的自动装配,把过滤结果(集合)封装为AutoConfigurationEntry
代码@11和代码12作用是为了后续对自动装配类的排序,排序是通过@AutoConfigureOrder、@AutoConfigureBefore、@AutoConfigureAfter。
接着看过滤的核心功能
//org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.getAutoConfigurationEntry(AutoConfigurationMetadata, AnnotationMetadata)
//传入参数autoConfigurationMetadata是加载了spring-autoconfigure-metadata.properties文件的对象
//传入参数annotationMetadata通常表示的springboot启动类的直接注解对象@SpringBootApplication(如果启动类上加了其它的@XXEnable,那么就是多个),是个StandardAnnotationMetadata,StandardAnnotationMetadata.annotations是这个配置类上的直接注解数量(其实就是java.lang.Class.getAnnotations() 方法返回当前这个元素上的所有直接注释),StandardAnnotationMetadata.introspectedClass就是springboot启动类
protected AutoConfigurationEntry getAutoConfigurationEntry(
AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {//如果环境变量存在spring.boot.enableautoconfiguration=false,则不启用自动装配
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);//代码@13
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);//代码@14
configurations = removeDuplicates(configurations);//代码@15
Set<String> exclusions = getExclusions(annotationMetadata, attributes);//代码@16
checkExcludedClasses(configurations, exclusions);//代码@17
configurations.removeAll(exclusions);//代码@18
configurations = filter(configurations, autoConfigurationMetadata);//代码@19,核心
fireAutoConfigurationImportEvents(configurations, exclusions);//代码@20
return new AutoConfigurationEntry(configurations, exclusions);//代码@21
}
代码@13:获取@EnableAutoConfiguration的属性,就是exclude和excludeName,用于排除自动装配。如果需要排除一些自动装配,可以在启动类上@SpringBootApplication(exclude = {RabbitAutoConfiguration.class,BatchAutoConfiguration.class}),这样就不会自动装配rabbitmq,spring bactch。
代码@14:加载spring.factories文件内的org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的类到集合。这些都是自动装配类型。
代码@15:移除重复的自动装配类,防止用户开发的spring.factories文件内配置了重复的自动装配。
代码@16:获取排除自动装配类的名称集合。排除自动装配除了exclude外,还可以通过配置属性spring.autoconfigure.exclude来指定要排除的自动装配。
代码@17:检查如果排除的类不在spring.factories的org.springframework.boot.autoconfigure.EnableAutoConfiguration内,则抛出异常。
代码@18:从自动配置类移除排除的自动装配。
代码@19:这个是自动装配过滤的核心方法。就是根据spring-autoconfigure-metadata.properties内的条件来过滤spring.factories内的org.springframework.boot.autoconfigure.EnableAutoConfiguration自动装配类。
代码@20:事件机制,用作钩子。触发AutoConfigurationImportEvent事件,用户可以实现AutoConfigurationImportListener对AutoConfigurationImportEvent事件做出对应动作。这里的configurations是经过过滤后,符合自动装配的类。这里的AutoConfigurationImportListener要写到spring.factories内,默认是ConditionEvaluationReportAutoConfigurationImportListener。这里默认执行的是ConditionEvaluationReportAutoConfigurationImportListener.onAutoConfigurationImportEvent(AutoConfigurationImportEvent)
代码@21:把符合自动装配的类集合和排除自动装配类集合包装为AutoConfigurationEntry返回。
下面看自动装配过滤分析
private List<String> filter(List<String> configurations,
AutoConfigurationMetadata autoConfigurationMetadata) {
long startTime = System.nanoTime();
String[] candidates = StringUtils.toStringArray(configurations);
boolean[] skip = new boolean[candidates.length];
boolean skipped = false;
for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {//@22
invokeAwareMethods(filter);//@23
boolean[] match = filter.match(candidates, autoConfigurationMetadata);//@24-begin
for (int i = 0; i < match.length; i++) {
if (!match[i]) {
skip[i] = true;
candidates[i] = null;
skipped = true;
}
}//@24-end
}
if (!skipped) {//@25
return configurations;
}
List<String> result = new ArrayList<>(candidates.length);//@26-begin
for (int i = 0; i < candidates.length; i++) {
if (!skip[i]) {
result.add(candidates[i]);
}
}//@26-end
return new ArrayList<>(result);
}
传入参数:
configurations:是spring.factories内的org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的自动装配类。
autoConfigurationMetadata:是spring-autoconfigure-metadata.properties文件内的属性集合,用于过滤自动装配类。
代码@22:遍历spring.factories内的org.springframework.boot.autoconfigure.AutoConfigurationImportFilter过滤器,排序后即[OnClassCondition, OnWebApplicationCondition, OnBeanCondition]
代码@23:如果过滤器是BeanClassLoaderAware、BeanFactoryAware、EnvironmentAware、ResourceLoaderAware类型,则赋值过滤器属性。
代码@24:执行的分别是OnClassCondition, OnWebApplicationCondition, OnBeanCondition的match方法,匹配的话match[i]就是true,把对应的candidates[i]位置的自动装配类设置为null。candidates集合就是spring.factories的org.springframework.boot.autoconfigure.EnableAutoConfiguration。那么是如何实现过滤的呢?以OnClassCondition为例,把org.springframework.boot.autoconfigure.EnableAutoConfiguration内的org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration加上ConditionalOnClass,即org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration.ConditionalOnClass是否在spring-autoconfigure-metadata.properties文件内存在,存在则candidates[i]位置不变,否则设置candidates[i]为null。就是这么简单进行过滤的。
过滤总结如下:
OnClassCondition过滤:自动装配类.ConditionalOnClass在spring-autoconfigure-metadata.properties内存在
OnWebApplicationCondition过滤:自动装配类.ConditionalOnWebApplication在spring-autoconfigure-metadata.properties内存在
OnBeanCondition过滤:自动装配类.ConditionalOnBean在spring-autoconfigure-metadata.properties内存在 或者 自动装配类.ConditionalOnSingleCandidate在spring-autoconfigure-metadata.properties内存在
代码@25:如果自动装配都有没有被过滤掉一个,则直接返回所有的自动装配。通常不会,因为一个项目不可能把springboot的每个组件都引入了。
代码@26:把经过过滤后剩余的自动装配类集合保存到result返回。
以上是自动装配的过滤流程,下面看自动装配的具体实现:
继续回到下面代码
grouping.getImports()返回的就是经过spring-autoconfigure-metadata.properties过滤后的自动装配类集合,对每个自动装配类处理其上的@Import注解。
接着看ConfigurationClassParser.processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, boolean checkForCircularImports)方法,该方法传入的configClass表示的是启动主类,currentSourceClass就是自动装配类,以自动装配AOP AopAutoConfiguration为例,接着执行的是ConfigurationClassParser.processConfigurationClass(ConfigurationClass configClass),判断自动装配类是否要进行装配代码如下
//传入参数configClass表示的就是自动装配类,比如AopAutoConfiguration
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
//省略其它代码, 自动装配 doProcessConfigurationClass
}
//自动装配类是否要进行跳过装配判断
//传入参数metadata是AnnotationMetadataReadingVisitor,即表示自动装配类上所有直接注解,比如 AopAutoConfiguration,注解是@Configuration、@ConditionalOnClass、@ConditionalOnProperty
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {//未被@Conditional(包括@ConditionalOnXXX)注解,则说明不需要跳过,需要进行装配
return false;
}
if (phase == null) {
if (metadata instanceof AnnotationMetadata &&
ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
}
return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
}
List<Condition> conditions = new ArrayList<>();
for (String[] conditionClasses : getConditionClasses(metadata)) {//getConditionClasses(metadata)是获取@Conditional的值
for (String conditionClass : conditionClasses) {
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
conditions.add(condition);
}
}//把自动装配类上@Conditional的value实例化保持到conditions集合
AnnotationAwareOrderComparator.sort(conditions);//按照@Order排序
for (Condition condition : conditions) {
ConfigurationPhase requiredPhase = null;
if (condition instanceof ConfigurationCondition) {
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
}
if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {//condition.matches()方法进行匹配,比如AopAutoConfiguration的@ConditionalOnClass,如果可以加载到EnableAspectJAutoProxy.class, Aspect.class, Advice.class,AnnotatedElement.class,则说明可以进行自动装配
return true;
}
}
return false;
}
自动装配流程总结:
自动装配核心是根据spring-autoconfigure-metadata.properties来过滤spring.factories文件内的自动装配类,然后把经过过滤后的自动配置集合再根据@ConditionalOnXXX决定是否要进行自动装配,,进而处理自动装配类。这里涉及到两次过滤,分别是AutoConfigurationImportFilter和SpringBootCondition,见下图的蓝色部分
自动装配流程图
核心getAutoConfigurationEntry(AutoConfigurationMetadata, AnnotationMetadata)方法的执行堆栈
自动装配疑问和解决
为什么要经过两次过滤呢?第一次的过滤(spring-autoconfigure-metadata.properties)是为了加快启动速度,实际没有也没关系(实际装配是以第二次过滤为结果进行装配),试想下,springboot目前很庞大了,引入了许多组件,如果直接在processConfigurationClass()方法内一个个的进行过滤,这样耗时就会长,启动就会慢,所以先进行一波过滤自动装配类。但是通过github查看springboot源码,发现spring-autoconfigure-metadata.properties在spring-boot-autoconfigure并不存在,但是实际项目中spring-boot-autoconfigure-2.1.3.RELEASE.jar中存在,这样是为什么呢?因为在springboot编译为jar时候,是通过spring-boot-autoconfigure-processor进行编译得来的,同时看到spring-boot-autoconfigure-2.1.3.RELEASE.jar内存在/META-INF/spring-configuration-metadata.json、/META-INF/additional-spring-configuration-metadata.json,这两个文件是用于用户写properties时候的自动提醒功能(比如在ide中输入logging. 会提醒输入level),这个可有可无,当然有了更好,方便用户,spring-configuration-metadata.json内容是springboot自动生成,additional-spring-configuration-metadata.json是对前者的补充,框架开发者手工维护。 spring-configuration-metadata.json文件是由spring-boot-configuration-processor生成。
自动装配实战
开发者要自定义一个配置类XXXAutoConfiguration,要在该配置类上加@Configuration,如果有开启条件,加上@ConditionalOnXXX,同时要把XXXAutoConfiguration加入到spring.factories文件内的org.springframework.boot.autoconfigure.EnableAutoConfiguration节点内。
如果自动装配类不加入到spring.factories文件内,那么写一个对应的EnableXXX也可以,在EnableXXX的@Import(ImportSelector类型),其中ImportSelector类型的selectImports方法自动装配类,这样自动装配类也会被注册为bean。
自动装配的核心就是@Conditional,根据不同的条件来进行装配,下面分析@Conditional
@Conditional原理与实战
@Conditional原理分析
以@ConditionalOnClass为例分析,比如要加上注解@Conditional,对应的处理类是OnClassCondition
在《 自动装配流程图》内通过spring-autoconfigure-metadata.properties进行过滤的时候(第一个蓝色方框图处),使用的是OnClassCondition、OnWebApplicationCondition、OnBeanCondition,执行的是match方法(AutoConfigurationImportFilter接口)进行匹配过滤;在真正装配的时候(第二个蓝色方框图处)比如配置类上有@ConditionalOnClass,那么执行matches方法(Condition接口)。关系如下图所示
AutoConfigurationImportFilter接口之FilteringSpringBootCondition分析
自动装配类集合的第一次过滤(通过spring-autoconfigure-metadata.properties过滤),依次过滤的是OnClassCondition、OnWebApplicationCondition、OnBeanCondition,入口是AutoConfigurationImportSelector.filter(List配置类.ConditionalOnClass是否在spring-autoconfigure-metadata.properties存在,存在则匹配,否则就过滤掉。
同理
OnBeanCondition是判断配置类.ConditionalOnBean或者配置类.ConditionalOnSingleCandidate是否在spring-autoconfigure-metadata.properties存在,存在则匹配,否则就过滤掉。
ConditionalOnWebApplication是判断配置类.OnWebApplicationCondition是否在spring-autoconfigure-metadata.properties存在,存在则匹配,否则就过滤掉。
开发自定义的OnXXXCondition在spring-boot-autoconfigure.properties内进行过滤步骤
在spring.factories的org.springframework.boot.autoconfigure.AutoConfigurationImportFilter节点加入自定义的OnXXXCondition,同时开发OnXXXCondition继承FilteringSpringBootCondition,实现getOutcomes方法即可。
Condition接口之SpringBootCondition
自动配置类装配前,通过@Conditional判断是否符合装配条件。具体实现就是OnXXXCondition.class。
自定义@ConditionalOnXXX的步骤:
在@ConditionalOnXXX上添加注解@Conditional(OnXXXCondition.class),开发OnXXXCondition继承SpringBootCondition重写getOutcomes方法即可。
自定义@ConditionalOnXXX,实战
写个@ConditionalOnActivatedMonitor,当环境存在my.endpoint.monitor.XXX.enable=true时候激活XXX监控,用法@ConditionalOnActivatedMonitor(name = "jvm")
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnActivatedMonitorCondition.class)
public @interface ConditionalOnActivatedMonitor {
/**
* The name of the monitor.
*
* @return the name of the health indicator
*/
String name();
/**
* 默认是启用状态
*/
boolean enabled() default true;
}
public class OnActivatedMonitorCondition extends OnEndpointElementCondition {
public static final String PREFIX = "my.endpoint.monitor.";
private final String prefix;
private final Class<? extends Annotation> annotationType;
public OnActivatedMonitorCondition() {
this(PREFIX, ConditionalOnActivatedMonitor.class);
}
public OnActivatedMonitorCondition(String prefix, Class<? extends Annotation> annotationType) {
this.prefix = prefix;
this.annotationType = annotationType;
}
//自动装配,实现getMatchOutcome即可
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
AnnotationAttributes annotationAttributes = AnnotationAttributes
.fromMap(metadata.getAnnotationAttributes(annotationType.getName()));//获取@ConditionalOnActivatedMonitor的属性
String healthIndicator = annotationAttributes.getString("name");
boolean enabled = annotationAttributes.getBoolean("enabled");
Environment environment = context.getEnvironment();
String enabledProperty = prefix + healthIndicator + ".enabled";
boolean match = environment.getProperty(enabledProperty, Boolean.class, enabled);//环境存在该变量为true则激活
return new ConditionOutcome(match,
ConditionMessage.forCondition(annotationType)
.because(enabledProperty + " is " + match));
}
}
自动装配类的顺序
配置类的装配顺序由@AutoConfigureOrder、@AutoConfigureBefore、@AutoConfigureAfter决定
@AutoConfigureOrder指定装配类的装配顺序
@AutoConfigureBefore在某个装配类之前进行装配
@AutoConfigureAfter在某个装配类之后进行装配
具体执行地方是
执行堆栈是
开发者如果要定义装配顺序,只需要写上以上三种中的顺序即可。
自定义starter
starter是个包集合,引入了这个,就引入了相关的依赖,比如引入spring-boot-starter-aop,那么就引入了spring-aop、aspectjweaver,就完成了自动装配。为什么就可以引入相关依赖呢?因为spring-boot-starter-aop-2.1.5.RELEASE.jar内就引入了spring-aop、aspectjweaver,在maven拉包的时候就会拉取pom文件spring-boot-starter-aop-2.1.5.RELEASE.pom,该XX.pom就是starter内的pom.xml。 实际查看spring-boot-starter-aop-2.1.5.RELEASE.jar时候里面是没有pom.xml的。
自定义starter步骤就是:
1.创建一个maven模块项目XXX-spring-boot,在该项目下创建spring.factories,增加org.springframework.boot.autoconfigure.EnableAutoConfiguration=XXXAutoConfiguration,然后开发好自动配置XXXAutoConfiguration
2.创建starter项目XXX-spring-boot-starter,里面只有一个pom.xml即可,该pom.xml要引入第1步的XXX-spring-boot
3.把XXX-spring-boot和XXX-spring-boot-starter上传到仓库,这样别的项目组就可以直接引用。
可以直接参考rocket springboot starter https://github.com/apache/rocketmq-spring
PS:
pring 官方的推荐写artifactId的方法是这样
官方命名格式为: spring-boot-starter-{name}
非官方建议命名格式:{name}-spring-boot-starter,通常自定义starter是这个名称规则