承接上文Spring5源码-BeanFactoryPostProcessor接口分析
前文已经介绍了ConfigurationClassPostProcessor的功能,并且在invokeBeanFactoryPostProcessors(beanFactory)方法中会被调用,接下来分析它是如何运作的。
1、获取所有已经注册的BeanDefinition,判断是否为配置候选类(是否有@Configuration、@Component、@ComponentScan、@Import、@ImportResource、方法上有@Bean,只要符合其中一个,就是配置候选类)
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
//获取所有已经注册的BeanDefinition的beanName
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
//在checkConfigurationClassCandidate方法内部会给配置类的BeanDefinition设置属性CONFIGURATION_CLASS_ATTRIBUTE,值为Full或Lite
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
//判断给定的类是否为配置候选类(是否有@Configuration、@Component、@ComponentScan、@Import、@ImportResource、方法上有@Bean)
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
......
}
ConfigurationClassUtils#checkConfigurationClassCandidate方法
public static boolean checkConfigurationClassCandidate(
BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
......
//获取@Configuration
Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
//proxyBeanMethods:为了让使用 @Bean 注解的方法被代理而实现 bean 的生命周期的行为
//设置为 true,那么直接调用方法获取 bean,不会创建新的 bean,而是会走 bean 的生命周期的行为。
//设置为 false, 那么直接调用方法获取 bean,会创建新的 bean,且不会走 bean 的生命周期的行为。
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
//是配置类且proxyBeanMethods=true,设置CONFIGURATION_CLASS_ATTRIBUTE为Full
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
else if (config != null || isConfigurationCandidate(metadata)) {
//是配置类且proxyBeanMethods=false,
//或者是 Component、ComponentScan、Import、ImportResource、方法上有@Bean
//则设置CONFIGURATION_CLASS_ATTRIBUTE为Lite
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
else {
return false;
}
......
}
public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
// Do not consider an interface or an annotation...
if (metadata.isInterface()) {
return false;
}
// candidateIndicators的值在静态代码块中进行添加,其值为Component、ComponentScan、Import、ImportResource对应的类名
for (String indicator : candidateIndicators) {
if (metadata.isAnnotated(indicator)) {
return true;
}
}
// Finally, let's look for @Bean methods...
//判断是否有@Bean注解的方法
return hasBeanMethods(metadata);
}
2、遍历配置候选类,调用ConfigurationClassParser的parse方法依次进行解析,真正干活的是doProcessConfigurationClass方法。其解析步骤如下:
① 如果配置候选类有@Component注解,则解析其内部类
② 处理@PropertySource注解
③ 处理@ComponentScans、@ComponentScan注解
④ 处理@Import 注解
⑤ 处理配置候选类下的@Bean注解
⑥ 处理配置候选类对应接口中的默认方法
⑦ 继续解析配置候选类的父类
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
......
// Recursively process the configuration class and its superclass hierarchy.
//递归解析当前配置候选类及其父类
SourceClass sourceClass = asSourceClass(configClass, filter);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {
//如果配置候选类有Component注解,则解析其内部类
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass, filter);
}
// Process any @PropertySource annotations
//如果配置候选类有@PropertySource注解,则处理PropertySource
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
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
//如果配置候选类有@ComponentScans、@ComponentScan注解,则处理
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
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// Process any @Import annotations
//处理配置候选类有@Import 注解
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
// Process any @ImportResource annotations
//处理配置候选类有@ImportResource
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注解
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
//处理接口中的默认方法
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;
}
3、如果配置候选类有Component注解,则判断其内部类是否满足配置候选类条件,满足则调用processConfigurationClass方法进行解析。
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass,
Predicate<String> filter) throws IOException {
//获取内部类
Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
if (!memberClasses.isEmpty()) {
List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
for (SourceClass memberClass : memberClasses) {
if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
candidates.add(memberClass);
}
}
OrderComparator.sort(candidates);
for (SourceClass candidate : candidates) {
if (this.importStack.contains(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
processConfigurationClass(candidate.asConfigClass(configClass), filter);
}
finally {
this.importStack.pop();
}
}
}
}
}
比如有以下代码,首先解析ConfigClass,执行doProcessConfigurationClass方法时,发现有@Component注解(@Configuration继承@Component),则获取内部类(MemberConfigClass和MemberConfigClass1),遍历发现MemberConfigClass满足配置候选类的条件,于是开始解析,等到MemberConfigClass解析完后,再回来解析ConfigClass,最后发现有父类,则继续解析父类BaseConfigClass。最终得到的Bean有configClass、com.test.config.ConfigClass$MemberConfigClass、myInnerNestClass1、myOuterNestClass、myBaseBean,而BaseConfigClass未被解析为Bean。
package com.test.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ConfigClass extends BaseConfigClass{
@Bean
public OuterNestClass myOuterNestClass() {
return new OuterNestClass();
}
class MemberConfigClass{
@Bean
public InnerNestClass myInnerNestClass1() {
return new InnerNestClass();
}
}
class MemberConfigClass1{
public InnerNestClass myInnerNestClass2() {
return new InnerNestClass();
}
}
}
class OuterNestClass{ }
class InnerNestClass{ }
@Component
public class BaseConfigClass {
@Bean
public BaseBean myBaseBean() {
return new BaseBean();
}
}
class BaseBean{}
4、处理@PropertySource注解,比较简单,把指定的配置文件存到StandardEnvironment对象的propertySources中。未解析任何的BeanDefinition。
private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
String name = propertySource.getString("name");
if (!StringUtils.hasLength(name)) {
name = null;
}
String encoding = propertySource.getString("encoding");
if (!StringUtils.hasLength(encoding)) {
encoding = null;
}
//获取PropertySource注解中配置的路径
String[] locations = propertySource.getStringArray("value");
Assert.isTrue(locations.length > 0, "At least one @PropertySource(value) location is required");
boolean ignoreResourceNotFound = propertySource.getBoolean("ignoreResourceNotFound");
Class<? extends PropertySourceFactory> factoryClass = propertySource.getClass("factory");
PropertySourceFactory factory = (factoryClass == PropertySourceFactory.class ?
DEFAULT_PROPERTY_SOURCE_FACTORY : BeanUtils.instantiateClass(factoryClass));
for (String location : locations) {
try {
String resolvedLocation = this.environment.resolveRequiredPlaceholders(location);
Resource resource = this.resourceLoader.getResource(resolvedLocation);
//添加到StandardEnvironment对象的propertySources中
addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding)));
}
catch (IllegalArgumentException | FileNotFoundException | UnknownHostException | SocketException ex) {
// Placeholders not resolvable or resource not found when trying to open it
if (ignoreResourceNotFound) {
if (logger.isInfoEnabled()) {
logger.info("Properties location [" + location + "] not resolvable: " + ex.getMessage());
}
}
else {
throw ex;
}
}
}
}
private void addPropertySource(PropertySource<?> propertySource) {
String name = propertySource.getName();
//获取Environment中已有的PropertySources
MutablePropertySources propertySources = ((ConfigurableEnvironment) this.environment).getPropertySources();
if (this.propertySourceNames.contains(name)) {
// We've already added a version, we need to extend it
PropertySource<?> existing = propertySources.get(name);
if (existing != null) {
PropertySource<?> newSource = (propertySource instanceof ResourcePropertySource ?
((ResourcePropertySource) propertySource).withResourceName() : propertySource);
if (existing instanceof CompositePropertySource) {
((CompositePropertySource) existing).addFirstPropertySource(newSource);
}
else {
if (existing instanceof ResourcePropertySource) {
existing = ((ResourcePropertySource) existing).withResourceName();
}
CompositePropertySource composite = new CompositePropertySource(name);
composite.addPropertySource(newSource);
composite.addPropertySource(existing);
propertySources.replace(name, composite);
}
return;
}
}
if (this.propertySourceNames.isEmpty()) {
propertySources.addLast(propertySource);
}
else {
String firstProcessed = this.propertySourceNames.get(this.propertySourceNames.size() - 1);
propertySources.addBefore(firstProcessed, propertySource);
}
this.propertySourceNames.add(name);
}
5、处理@ComponentScans、@ComponentScan注解
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
//交给ComponentScanAnnotationParser来解析
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
//遍历解析后的BeanDefinition,如果满足配置候选类,继续解析
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
ComponentScanAnnotationParser#parse()
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, String declaringClass) {
//真正干活的是ClassPathBeanDefinitionScanner ,之前接触过
//useDefaultFilters是否使用默认的Filters,默认是true,即扫描带有@Component @Repository @Service @Controller 的组件
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
//接下来是给scanner设置相关属性对应的值,@ComponentScan定义了很多属性可以手动设置
//设置BeanName生成策略 默认BeanNameGenerator,用于给扫描到的Bean生成BeanName
Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
BeanUtils.instantiateClass(generatorClass));
//scopedProxy:设置代理方式,no(默认值):如果有接口就使用JDK代理,如果没有接口就使用CGLib代理
//interfaces: JDK代理 targetClass:CGLib代理
ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
scanner.setScopedProxyMode(scopedProxyMode);
}
else {
Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
}
//resourcePattern:配置要扫描的资源的正则表达式的,默认是"**/*.class",即配置类包下的所有class文件。
scanner.setResourcePattern(componentScan.getString("resourcePattern"));
//添加包含过滤器
for (AnnotationAttributes includeFilterAttributes : componentScan.getAnnotationArray("includeFilters")) {
List<TypeFilter> typeFilters = TypeFilterUtils.createTypeFiltersFor(includeFilterAttributes, this.environment,
this.resourceLoader, this.registry);
for (TypeFilter typeFilter : typeFilters) {
scanner.addIncludeFilter(typeFilter);
}
}
//添加排除过滤器
for (AnnotationAttributes excludeFilterAttributes : componentScan.getAnnotationArray("excludeFilters")) {
List<TypeFilter> typeFilters = TypeFilterUtils.createTypeFiltersFor(excludeFilterAttributes, this.environment,
this.resourceLoader, this.registry);
for (TypeFilter typeFilter : typeFilters) {
scanner.addExcludeFilter(typeFilter);
}
}
//是否是懒加载
boolean lazyInit = componentScan.getBoolean("lazyInit");
if (lazyInit) {
scanner.getBeanDefinitionDefaults().setLazyInit(true);
}
//设置包名,没有就默认配置类所在的包
Set<String> basePackages = new LinkedHashSet<>();
String[] basePackagesArray = componentScan.getStringArray("basePackages");
for (String pkg : basePackagesArray) {
String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
Collections.addAll(basePackages, tokenized);
}
for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
basePackages.add(ClassUtils.getPackageName(clazz));
}
if (basePackages.isEmpty()) {
basePackages.add(ClassUtils.getPackageName(declaringClass));
}
//扫描时把当前配置类排除掉
scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
@Override
protected boolean matchClassName(String className) {
return declaringClass.equals(className);
}
});
//开始扫描
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
ClassPathBeanDefinitionScanner#doScan方法
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
// 扫描basePackages下所有的文件,进行include、exclude、@Conditional判断后返回BeanDefinition
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
// scope解析:单例与多例
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
// 生成beanName:默认是类名首字母小写,如果@Component中指定了name则使用指定的name
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
// 解析@Lazy、@Primary、@DependsOn、@Role、@Description
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
// 注册BeanDefinition: beanDefinitionMap.put(beanName, beanDefinition)
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
else {
return scanCandidateComponents(basePackage);
}
}
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
//我的包为com.test.cs,组装扫描路径:classpath*:com/test/cs/**/*.class
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (Resource resource : resources) {
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
try {
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
//进行include、exclude、@Conditional判断后返回BeanDefinition
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(resource);
//进一步判断,需满足(非嵌套类且能实例化 或者 非嵌套类并且是有@Lookup的抽象类)
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
}
......
}
}
......
}
}
......
return candidates;
}
//进行include、exclude、@Conditional判断后返回BeanDefinition
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
//执行include、exclude 过滤
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return false;
}
}
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
//@Conditional判断
return isConditionMatch(metadataReader);
}
}
return false;
}
//类必须是独立的(不是嵌套类),并且要么是具体类(可以实例化),要么是抽象类并且具有某些特定注解(如 @Lookup)的方法。
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
AnnotationMetadata metadata = beanDefinition.getMetadata();
return (metadata.isIndependent() && (metadata.isConcrete() ||
(metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
}
④ 处理@Import 注解,该注解可以注册普通组件类、实现ImportSelector接口的实现类、实现ImportBeanDefinitionRegistrar接口的实现类。示例代码如下:
@Import({ImportClass.class, MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})
public class Application {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
System.out.println(String.join("\r\n",context.getBeanDefinitionNames()));
}
}
class ImportClass {}
@Import(ImportClass5.class)
class ImportClass1 {}
class ImportClass2 {}
class ImportClass3 {}
class ImportClass4 {}
class ImportClass5 {}
public class MyImportSelector implements ImportSelector {
/**
* @param importingClassMetadata 当前标识Import注解的类的所有注解信息
* @return 返回组件的全类名
*/
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.test.importcfg.ImportClass1", "com.test.importcfg.ImportClass2"};
}
}
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
*
* @param importingClassMetadata 标识Import注解的类的所有注解信息
* @param registry Bean定义的注册类
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
RootBeanDefinition rootBeanDefinition3 = new RootBeanDefinition(ImportClass3.class);
registry.registerBeanDefinition("importClass3",rootBeanDefinition3);
RootBeanDefinition rootBeanDefinition4 = new RootBeanDefinition(ImportClass4.class);
registry.registerBeanDefinition("importClass4",rootBeanDefinition4);
}
}
//结果
application
com.test.importcfg.ImportClass
com.test.importcfg.ImportClass5
com.test.importcfg.ImportClass1
com.test.importcfg.ImportClass2
importClass3
importClass4
源码分析
//getImports方法返回所有@Import注解的value集合
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
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) {
//如果实现了ImportSelector接口
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
//实例化ImportSelector 实现类
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
this.environment, this.resourceLoader, this.registry);
Predicate<String> selectorFilter = selector.getExclusionFilter();
if (selectorFilter != null) {
exclusionFilter = exclusionFilter.or(selectorFilter);
}
//如果是DeferredImportSelector类型,则添加到List<DeferredImportSelectorHolder>中,等所有都注册完成后再注册
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
//调用接口方法
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter); //递归调用(因为导入的类上可能又有import注解)
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
}
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实现类
ImportBeanDefinitionRegistrar registrar =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
//放到当前解析的配置类的importBeanDefinitionRegistrars Map中保存
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
//未实现任何接口,当成配置类处理,此种情况导入的类上又有import注解也能被解析
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
}
}
}
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();
}
}
}
⑤ 处理配置候选类下的@Bean注解
// 检索所有的@Bean的元数据,然后添加到对应的配置类beanMethods集合中
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
private Set<MethodMetadata> retrieveBeanMethodMetadata(SourceClass sourceClass) {
AnnotationMetadata original = sourceClass.getMetadata();
Set<MethodMetadata> beanMethods = original.getAnnotatedMethods(Bean.class.getName());
if (beanMethods.size() > 1 && original instanceof StandardAnnotationMetadata) {
// Try reading the class file via ASM for deterministic declaration order...
// Unfortunately, the JVM's standard reflection returns methods in arbitrary
// order, even between different runs of the same application on the same JVM.
try {
AnnotationMetadata asm =
this.metadataReaderFactory.getMetadataReader(original.getClassName()).getAnnotationMetadata();
Set<MethodMetadata> asmMethods = asm.getAnnotatedMethods(Bean.class.getName());
if (asmMethods.size() >= beanMethods.size()) {
Set<MethodMetadata> selectedMethods = new LinkedHashSet<>(asmMethods.size());
for (MethodMetadata asmMethod : asmMethods) {
for (MethodMetadata beanMethod : beanMethods) {
if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) {
selectedMethods.add(beanMethod);
break;
}
}
}
if (selectedMethods.size() == beanMethods.size()) {
// All reflection-detected methods found in ASM method set -> proceed
beanMethods = selectedMethods;
}
}
}
catch (IOException ex) {
logger.debug("Failed to read class file via ASM for determining @Bean method order", ex);
// No worries, let's continue with the reflection metadata we started with...
}
}
return beanMethods;
}
⑥ 处理配置候选类对应接口中的默认方法。当接口的默认方法上有@Bean注解时,也会被解析
private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
for (SourceClass ifc : sourceClass.getInterfaces()) {
//检索所有的@Bean的元数据
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(ifc);
for (MethodMetadata methodMetadata : beanMethods) {
if (!methodMetadata.isAbstract()) {
// A default method or other concrete method on a Java 8+ interface...
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
}
//递归调,比如父接口也有带@Bean的默认方法
processInterfaces(configClass, ifc);
}
}
比如有如下代码
public class Application implements ImportClass{
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
System.out.println(String.join("\r\n",context.getBeanDefinitionNames()));
}
}
interface ImportClass extends ImportClass2{
@Bean
default ImportClass1 getImportClass1(){
return new ImportClass1();
}
}
interface ImportClass2 {
@Bean
default ImportClass1 getImportClass2(){
return new ImportClass1();
}
}
class ImportClass1 {}
//结果
application
getImportClass1
getImportClass2
⑦ 继续解析配置候选类的父类
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();
}
}
到这里,解析完了,接下来就是BeanDefinition注册到容器中了
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
......
do {
StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
//在这里解析,解析的数据保存在各自配置类的相应属性中
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
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());
}
//调用ConfigurationClassBeanDefinitionReader的loadBeanDefinitions方法进行BeanDefinition注册
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();
......
}
while (!candidates.isEmpty());
......
}
总计
ConfigurationClassPostProcessor实现读懂后,相当于Spring Bean的注册方式就完全掌握了。
方式一:@Configuration + @Bean方式
方式二:使用@Component注解 + @ComponentScan包扫描方式
方式三:使用@Import方式,又分为3种:
① 注册普通类
② 实现ImportSelector接口的实现类,将selectImports返回的字符串数组解析为BeanDefinition注册到容器中。好处是:
- 把某个功能的相关类放到一起,方面管理和维护。
- 重写selectImports方法时,能够根据条件判断某些类是否需要被实例化,或者某个条件实例化这些bean,其他的条件实例化那些bean等,我们能够非常灵活的定制化bean的实例化。
- DeferredImportSelector是ImportSelector的子接口,提供了更灵活的导入时机,允许在所有的配置类都被解析和注册到Spring容器之后,再根据条件动态地选择并导入配置类。由于其执行时机较晚,它可以访问到由其他配置类定义的Bean实例,因此可以根据这些Bean的状态或属性来决定导入哪些配置类。
③ 实现ImportBeanDefinitionRegistrar接口的实现类。这种方式比ImportSelector更加灵活,可以自定义bean的名称、作用域等很多参数。
方式四:使用前文所说的实现BeanDefinitionRegistryPostProcessor或者BeanFactoryPostProcessor接口
参考文档:
Spring源码 - DeferredImportSelector实现分析
Spring中注册Bean的方式有哪些?