Spring component-scan源码分析(二) -- @Configuration注解处理
上篇文章Spring component-scan源码分析(一) – XML解析分析了Spring解析<context:component-scan …/>标签时,把扫描到的合适的类封装成BeanDefinition加入Sping容器中,本篇分析Spring如何解析带相关注解的类。
从AnnotationConfigUtils的registerAnnotationConfigProcessors静态方法入手
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
//设置成ContextAnnotationAutowireCandidateResolver类型的
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
//注册ConfigurationClassPostProcessor类,解析@Configuration注解
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
//注册AutowiredAnnotationBeanPostProcessor类
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
//是否支持JSR-250
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
//是否支持JPA
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();
try {
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
}
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
}
//注册EventListenerMethodProcessor类
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}
//注册DefaultEventListenerFactory类
if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
}
return beanDefs;
}
该方法想Spring容器注册了一些处理器,用于处理配置、注入等注解的处理
ConfigurationClassPostProcessor类
可以看到,ConfigurationClassPostProcessor类实现了BeanDefinitionRegistryPostProcessor、PriorityOrdered这两个接口。
(1). Spring在把所有bean解析封装成BeanDefinition装进容器后,在bean实例化之前,会实例化实现BeanDefinitionRegistryPostProcessor接口的bean,调用其postProcessBeanDefinitionRegistry方法,最后再调用BeanDefinitionRegistryPostProcessor接口的父类接口BeanFactoryPostProcessor接口的postProcessBeanFactory方法。这样bean可以在这两个方法中对容器中的bean属性进行一些处理。
(2). 实现PriorityOrdered接口有最高优先级,会优先实例化调用这样的BeanDefinitionRegistryPostProcessor,它比Ordered接口优先级高,而实现Ordered接口又比没实现这两个接口的优先级高
1 postProcessBeanDefinitionRegistry方法
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
...防止重复的处理
//记录处理过的registry
this.registriesPostProcessed.add(registryId);
//开始寻找符合的配置类
processConfigBeanDefinitions(registry);
}
processConfigBeanDefinitions方法开始处理@Configuration配置类
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
//已经处理过了,处理过的bean会在其BeanDefinition中添加一个属性作为标志
...省略log
}
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
//带有@Configuration注解或带有@Component、@ComponentScan、@Import、@ImportResource的注解或有带@Bean的方法的类加入候选集合
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
//没有候选的配置类,那不用处理了,收工
if (configCandidates.isEmpty()) {
return;
}
..省略@Order注解排序
...省略名字生成器处理
//environment没被赋值就新建一个StandardEnvironment
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
//用于解析带@Configuration参数的类
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
//【标记1】开始解析
parser.parse(candidates);
//验证解析得到的@Configuration类,由于CGLib的限制,类不能是final,并且@Bean方法要能被覆盖
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
//reader是负责注册beanDef进spring容器
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
//【标记2】开始向容器注册BeanDefinition
this.reader.loadBeanDefinitions(configClasses);
//加入已解析过的缓存中
alreadyParsed.addAll(configClasses);
//清空解析过的候选类
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
//进入这里,说明解析过程中,容器中新增了一些BeanDefinition
...
//一系列操作,提取出新的没解析的类赋值给candidates,循环再次解析
}
}
while (!candidates.isEmpty());
//注册ImportRegistry,用于处理ImportAware接口
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
...省略清理metadataReaderFactory的缓存
}
该方法代码很多,但逻辑还是清楚,主要从registry中筛选出@Configuration配置类进行解析,最后在把这些类封装成BeanDefinition加入Spring容器。
核心代码是parser.parse(candidates)和this.reader.loadBeanDefinitions(configClasses);
【标记1】开始解析
public void parse(Set<BeanDefinitionHolder> configCandidates) {
this.deferredImportSelectors = new LinkedList<>();
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
//会进入该if
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
...
}
catch ...
}
//处理需要延迟引入的配置
processDeferredImportSelectors();
}
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
//把类的元数据和beanName封装成ConfigurationClass
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
在上篇文章Spring component-scan源码分析(一) – XML解析可以知道扫描带有@Component注解的类会封装成ScannedGenericBeanDefinition放入Spring容器。
可以看到ScannedGenericBeanDefinition是实现了AnnotatedBeanDefinition接口的
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
//处理@Conditional注解
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;//跳过(即不满足条件)的话,直接返回
}
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {//已经解析过
if (configClass.isImported()) {//是被引入的
if (existingClass.isImported()) {//旧的类也是被引入的
existingClass.mergeImportedBy(configClass);//更新合并引入它配置类
}
// Otherwise ignore new imported config class; existing non-imported class overrides it.
return;
}
else {
//否则就把旧的从解析缓存中移除,也从父类缓存中移除
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
//把configClass又封装成SourceClass类型
SourceClass sourceClass = asSourceClass(configClass);
//会循环解析直到没有符合的父类
do {
//解析@Configuration配置类
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
//解析完装入缓存
this.configurationClasses.put(configClass, configClass);
}
前半部分代码会看不懂,先看doProcessConfigurationClass方法再回来看就明白了
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
//是否有@Component注解
if (sourceClass.getMetadata().isAnnotated(Component.class.getName())) {
//处理成员内部类
processMemberClasses(configClass, sourceClass);
}
// 处理@PropertySource注解
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
//StandardEnvironment实现了ConfigurableEnvironment接口
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
...省略log
}
}
...省略处理@ComponentScans、@ComponentScan注解,和处理XML配置处理差不多
//处理@Import注解(用于引入其他配置类)
processImports(configClass, sourceClass, getImports(sourceClass), true);
//处理@ImportResource注解(用于引入其他XML配置或.groovy文件配置)
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) {
//处理${xxx}的情况
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
//把资源加入当前解析类的缓存中
configClass.addImportedResource(resolvedResource, readerClass);
}
}
//拿到带@Bean注解的方法,而且顺序是和类中的源代码一致
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
//封装成BeanMethod,加入当前解析类缓存中
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
//处理实现接口中的带@Bean的默认方法(java8新增的default关键字)
processInterfaces(configClass, sourceClass);
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
//返回父类继续解析
return sourceClass.getSuperClass();
}
}
//解析完成
return null;
}
解析步骤:
1、如果有@Component注解,先解析成员内部类;
2、处理@PropertySource注解;
3、处理@ComponentScans、@ComponentScan注解,和处理XML配置<context:component-scan …/>差不多;
4、处理@Import注解(用于引入其他配置类),其中涉及ImportSelector、DeferredImportSelector、ImportBeanDefinitionRegistrar接口的处理;
5、处理@ImportResource注解(用于引入其他XML配置或.groovy文件配置);
6、处理带@Bean注解的方法;
7、处理实现接口中的带@Bean的默认方法(java8新增的default关键字);
8、如果有父类,且不是java原生类,且还没解析过,就继续解析父类
上面对带@Configuration注解的类解析了一遍,解析的结果信息都放在封装的ConfigurationClass里,接下来就是向Spring容器注册BeanDefinition了
【标记2】开始向容器注册BeanDefinition
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
//遍历解析好的ConfigurationClass
for (ConfigurationClass configClass : configurationModel) {
//真正注册逻辑在这
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
if (trackedConditionEvaluator.shouldSkip(configClass)) {
//进入这里说明要跳过该配置类
String beanName = configClass.getBeanName();
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
this.registry.removeBeanDefinition(beanName);//从容器中移除该bean名字
}
//再从解析@Import得到的缓存中移除当前类
this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
return;
}
if (configClass.isImported()) {
//把当前的@Configuration类解析封装成AnnotatedGenericBeanDefinition,加入spring容器
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
//解析加载带@Bean注解的方法,会封装成ConfigurationClassBeanDefinition或RootBeanDefinition(代理模式的情况下)放入Spring容器
loadBeanDefinitionsForBeanMethod(beanMethod);
}
//加载@ImportResource注解配置文件的bean,这就涉及到XML解析了
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
//调用实现ImportBeanDefinitionRegistrar接口的对象的registerBeanDefinitions方法
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
注册一个带@Configuration注解的bean的流程:
1、 先注册自身类
2、 注册解析到的带@Bean注解的方法中的bean
3、 注册@ImportResource注解配置文件的bean
4、 调用实现ImportBeanDefinitionRegistrar接口的对象的registerBeanDefinitions方法,对Spring容器做更多的操作
上面对postProcessBeanDefinitionRegistry方法分析告一段落,接着分析跟随其后被Spring调用的postProcessBeanFactory方法
2 postProcessBeanFactory方法
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
...防止重复的处理
//判断是否解析过
if (!this.registriesPostProcessed.contains(factoryId)) {
//这个方法上面分析过
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
//对解析好的@Configuration类进行CGLib代理,代理类会实现EnhancedConfiguration接口
enhanceConfigurationClasses(beanFactory);
//做了两件事:
// (1)、对EnhancedConfiguration类型的bean调用其BeanFactoryAware接口的setBeanFactory方法
// (2)、处理实现ImportAware接口的类
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
该方法主要是对没处理过的BeanDefinitionRegistry进行处理,然后就是对解析好的@Configuration类进行CGLib代理,最后就是添加一个后置处理器ImportAwareBeanPostProcessor。
总结
Spring通过遍历容器得到配置类,处理他们的相关注解,向容器中注册更多的bean,最后再用CGLib代理技术代理配置类以达到管理bean生命周期的目的。
PS:
想着控制篇幅,更多展开分析的代码就不贴了。