目錄
本文能幫你解答的問題
類介紹
作用
類繼承關系
Aware
Ordered
BeanDefinitionRegistryPostProcessor
BeanFactoryPostProcessor
添加ConfigurationClassPostProcessor的政策
方法源碼解讀
postProcessBeanDefinitionRegistry
step1. 尋找所有配置類的BeanDefinition
step2. 排序配置類
step3. 解析配置類及部分beanDefinition的注冊
step4. 完成@Bean、@Import等bean的解析與注冊
postProcessBeanFactory
CGLIB增強Configuration類
添加ImportAwareBeanPostProcessor
總結
關于-BeanFactory後置處理器介紹見:Spring拓展機制之BeanFactoryPostProcessor
本文能幫你解答的問題
- ConfigurationClassPostProcessor的作用是什麼?
- @Configuration、@Component、@ComponentScan、@ComponentScans、@Bean、@Import等注解是如何完成bean注冊的?
- @Conditional注解如何控制配置類是否需要解析?
- @Configuration的bean為什麼要增強?增強了什麼邏輯?
類介紹
作用
非常重要的一個BeanFactory後置處理器,通過掃描配置類完成各種注解的解析,自動完成所有BeanDefinition的注冊。
例如通過對@ComponentScan、@Bean、@Import等注解的解析完成bean的注冊。
類繼承關系

繼承了3個Aware接口、用于控制執行順序的Ordered接口,以及BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor。
Aware
用于拿到ClassLoader、ResourceLoader以及Environment對象。
Ordered
通過實作getOrder控制執行該BeanFactory後置處理器的優先級。
ConfigurationClassPostProcessors實作的getOrder放回的是Integer.MAX_VALUE,用于保證最先執行。
了解BeanFactoryProcessor執行順序的知道,實作了PriorityOrdered的後置處理器會優先于實作了Ordered的後置處理器,是以ConfigurationClassPostProcessors還實作了PriorityOrdered以確定第一個執行。
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE; // within PriorityOrdered
}
BeanDefinitionRegistryPostProcessor
通過實作postProcessBeanDefinitionRegistry方法,能拿到BeanDefinitionRegistry對象,BeanDefinitionRegistry是注冊、修改BeanDefinition的重要類,是以通實作該方法可以向容器中對BeanDefinition進行自定義新增或者修改等。
BeanFactoryPostProcessor
通過實作postProcessBeanFactory,能拿到BeanFactory對象,是在所有到BeanDefinition注冊完成後,執行個體化前回調,進而可以對bean做進一步的修改
添加ConfigurationClassPostProcessor的政策
當開啟注解掃描bean,spring則會自動添加該BeanFactory後置處理器,來完成自動掃描注冊的bean。
xml的ApplicationContext環境下開啟方式:
<context:annotation-config/>或者<context:component-scan/>
對于AnnotationConfigApplicationContext預設會自動添加ConfigurationClassPostProcessor。(通過構造函數最終調用到AnnotationConfigUtils#registerAnnotationConfigProcessors()完成beanDefition添加,在refresh過程完成該bean的注冊)
方法源碼解讀
這裡從實作的postProcessBeanDefinitionRegistry和postProcessBeanFactory按照執行的先後順序進行分析。
其中觸發這兩個方法的時機都是在 AbstractApplicationContext#refresh的invokeBeanFactoryPostProcessors過程觸發。
AbstractApplicationContext#refresh
-->AbstractApplicationContext#invokeBeanFactoryPostProcessors
-->PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(beanFactory,beanFactoryPostProcessors)
postProcessBeanDefinitionRegistry
@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);
}
ConfigurationClassPostProcessor#processConfigBeanDefinitions:
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
/1. 尋找所有配置類的BeanDefinition
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
//是否是配置類,是則添加到待處理的集合中
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
//沒有return不處理
// Return immediately if no @Configuration classes were found
if (configCandidates.isEmpty()) {
return;
}
//2. 排序配置類
// 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);
});
//省略部分代碼
//準備好配置解析類
// Parse each @Configuration class
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 {
//3. 解析配置類
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());
}
//4. 注冊解析到的所有BeanDefinition
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
//省略部分代碼
}
while (!candidates.isEmpty());
//省略部分代碼
}
processConfigBeanDefinitions方法較長,這裡拆分幾個過程。
step1. 尋找所有配置類的BeanDefinition
從目前已經注冊的所有BeanDefinition中尋找屬于配置類的BeanDefinition,放到configCandidates,用于後續的處理。
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
//如果是配置類,是則放到configCandidates中
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
問題:什麼類才叫配置類?
帶着這個問題看下ConfigurationClassUtils.checkConfigurationClassCandidate方法邏輯。
public static boolean checkConfigurationClassCandidate(
BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
String className = beanDef.getBeanClassName();
if (className == null || beanDef.getFactoryMethodName() != null) {
return false;
}
//取得類上的注解資訊
AnnotationMetadata metadata;
if (beanDef instanceof AnnotatedBeanDefinition &&
className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
// Can reuse the pre-parsed metadata from the given BeanDefinition...
metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
}
else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
// Check already loaded Class if present...
// since we possibly can't even load the class file for this Class.
Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
//繼承了這些類的都不是配置類
if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
BeanPostProcessor.class.isAssignableFrom(beanClass) ||
AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
EventListenerFactory.class.isAssignableFrom(beanClass)) {
return false;
}
metadata = AnnotationMetadata.introspect(beanClass);
}
else {
//省略部分代碼
}
//擷取Configuration注解的值資訊
Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
//如果是@Configuration的bean,則屬于配置類,會設定CONFIGURATION_CLASS_ATTRIBUTE屬性為full。
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
//如果滿足isConfigurationCandidate,也是配置類,設定CONFIGURATION_CLASS_ATTRIBUTE屬性為lite
else if (config != null || isConfigurationCandidate(metadata)) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
else {
//都不滿足不是配置類。
return false;
}
// It's a full or lite configuration candidate... Let's determine the order value, if any.
//設定排序值用于後續對配置類進行排序處理
Integer order = getOrder(metadata);
if (order != null) {
beanDef.setAttribute(ORDER_ATTRIBUTE, order);
}
return true;
}
ConfigurationClassUtils#isConfigurationCandidate:
static {
candidateIndicators.add(Component.class.getName());
candidateIndicators.add(ComponentScan.class.getName());
candidateIndicators.add(Import.class.getName());
candidateIndicators.add(ImportResource.class.getName());
}
public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
// Any of the typical annotations found?
//隻要存在上面4種注解中的一種都是配置類
for (String indicator : candidateIndicators) {
if (metadata.isAnnotated(indicator)) {
return true;
}
}
// Finally, let's look for @Bean methods...
return metadata.hasAnnotatedMethods(Bean.class.getName());
}
總結一下配置類的定義:
- 有@Configuration注解的類
- 有Component、ComponentScan、Import、ImportResource注解的類
- 方法上有@Bean注解的類
特别說明:滿足1和滿足2、3對于配置類的beanDefinition的CONFIGURATION_CLASS_ATTRIBUTE值分别設定為full和lite的原因,這個在postProcessBeanFactory方法中會有答案。
step2. 排序配置類
根據@Order标注的順序來排序所有@Configuration标注的BeanDefinition
// 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);
});
step3. 解析配置類及部分beanDefinition的注冊
解析配置類中的各種注解,例如@ComponentScan、@Import、@Bean等,同時完成部分beanDefinition的注冊,類似與@Component注解的bean,@Configration的bean,對于@Import、@Bean指定的bean會在step4完成beanDefinition的注冊。
// Parse each @Configuration class
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 {
parser.parse(candidates);
parser.validate();
}
while (!candidates.isEmpty());
ConfigurationClassParser.parse調用鍊路:
ConfigurationClassParser#parse()
->ConfigurationClassParser#processConfigurationClass
->ConfigurationClassParser#doProcessConfigurationClass
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
//處理@Conditional注解,條件判斷目前配置類是否需要處理
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
//部分代碼省略
// Recursively process the configuration class and its superclass hierarchy.
SourceClass sourceClass = asSourceClass(configClass);
do {
//解析配置類的關鍵方法
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
//緩存起來,這裡得到的configClass就是經過解析後封裝好的ConfigurationClass,用于後續做經一步的處理
this.configurationClasses.put(configClass, configClass);
}
processConfigurationClass處理邏輯是先判斷目前配置類是否需要解析,如果需要則然後調用doProcessConfigurationClass去做解析。
@Conditional判斷配置類是否需要解析
通過ConditionEvaluator#shouldSkip(),判斷目前配置類是否需要解析,這裡傳入的phase參數為PARSE_CONFIGURATION,代表是解析配置階段。
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
//不存在@Conditional注解,無需跳過
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
return false;
}
//省略部分代碼
//一個配置類可能有很多@Conditional
List<Condition> conditions = new ArrayList<>();
for (String[] conditionClasses : getConditionClasses(metadata)) {
for (String conditionClass : conditionClasses) {
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
conditions.add(condition);
}
}
//排序
AnnotationAwareOrderComparator.sort(conditions);
//按順序調用matches方法
for (Condition condition : conditions) {
ConfigurationPhase requiredPhase = null;
//是否繼承的ConfigurationCondition,是,則取指定的判斷階段
if (condition instanceof ConfigurationCondition) {
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
}
//判斷如果目前處理階段和Condition指定的階段一緻,則調用match方法。
if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
return true;
}
}
return false;
}
特别說明:ConditionEvaluator#shouldSkip方法在兩個階段都會調用,一個是配置類的解析階段,一個是bean的注冊階段,如果需要指定隻在某個階段生效,需要實作ConfigurationCondition來指定處理的階段,ConfigurationPhase參數來區分不同的階段,具體使用參考
@PropertySource("classpath:test.properties")
// Process any @PropertySource annotations
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");
}
}
ConfigurationClassParser#processPropertySource:
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;
}
//配置檔案路徑
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 resource = this.resourceLoader.getResource(resolvedLocation);
//将封裝成的PropertySource添加到environment的PropertySources中
addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding)));
}
catch (IllegalArgumentException | FileNotFoundException | UnknownHostException ex) {
//代碼省略
}
}
}
@ComponentScan用于指定自動掃描bean的包路徑。
關于該注解的詳細用法參考
// Process any @ComponentScan annotations
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
//委托給componentScanParser完成bean的掃描與注冊
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
//周遊所有掃描到的BeanDefinition
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());
}
}
}
}
主幹邏輯:
- 根據包路徑掃描bean并注冊
- 如果是配置類,遞歸走配置類的解析,通過反複對配置類解析,最終完成所有掃描到的bean注冊
bean掃描并注冊過程委托給ComponentScanAnnotationParser#parse:
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
//nameGenerator,用于擷取bean名稱生成器,如果沒有配置,則取Spring預設
Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
BeanUtils.instantiateClass(generatorClass));
//scopedProxy,作用?
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 filter : componentScan.getAnnotationArray("includeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addIncludeFilter(typeFilter);
}
}
//過濾器,和includeFilters作用剛好相反,用來對掃描的類進行排除的,被排除的類不會被注冊到容器中
for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addExcludeFilter(typeFilter);
}
}
//是否延遲初始化被注冊的bean
boolean lazyInit = componentScan.getBoolean("lazyInit");
if (lazyInit) {
scanner.getBeanDefinitionDefaults().setLazyInit(true);
}
//basePackages:掃描包路徑
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);
}
//basePackageClasses:指定一些類,spring容器會掃描這些類所在的包及其子包中的類
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中,然後進一步委托給ClassPathBeanDefinitionScanner.doScan進行解析。
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) {
//掃描到所有的BeanDefinition。
//這裡的BeanDefinition隻是一個很原始的BeanDefinition,很多參數需要進一步設定
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
//周遊設定每一個BeanDefinition的參數
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
//scope
candidate.setScope(scopeMetadata.getScopeName());
//benaName
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
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的注冊
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
到這裡完成了所有掃描到的beanDefinition的注冊。
解析@Import
用于批量導入指定的bean,例如當某個Bean上沒有@Component注解時,或者隻是指定具體某幾個bean,則可以通過該注解完成指定bean的導入。
@Import除了導入普通的bean外,還可以導入如下幾種bean:
- @Configuration标注的類
- 繼承了ImportBeanDefinitionRegistrar的類
- 繼承了ImportSelector或者DeferredImportSelector的類
具體使用參考
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), true);
ConfigurationClassParser#processImports
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
//省略部分代碼
else {
this.importStack.push(configClass);
try {
//周遊了有@Import注解的所有類
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 selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
this.environment, this.resourceLoader, this.registry);
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
//遞歸調用processImports方法
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
//是否繼承了ImportBeanDefinitionRegistrar
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
//都不是,則作為配置類進行處理,實際是遞歸調用processConfigurationClass方法
else {
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
//省略部分代碼
}
}
主要對@Import注解标注的類分3種情況進行處理(ImportSelector、ImportBeanDefinitionRegistrar、普通類)。
ImportSelector
ImportSelector分兩種情況:
- 如果是直接實作的ImportSelector,則擷取到自定義的ImportSelector,調用selectImports擷取到要導入的指定bean,遞歸調用processImports,出口為processConfigurationClass方法。
- 如果是DeferredImportSelector,待所有配置類解析後才會執行導入。
//這個candidate就是解析到的@Import value指定的類
Class<?> candidateClass = candidate.loadClass();
//執行個體化實作的ImportSelectorbean
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
this.environment, this.resourceLoader, this.registry);
//如果實作的是DeferredImportSelector(ImportSelector的子類)
if (selector instanceof DeferredImportSelector) {
//将目前selector bean先緩存下來,這裡不執行selectImports
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
//直接實作的ImportSelector,直接調用selectImports,擷取importClassNames
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
//遞歸調用processImports
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
ImportBeanDefinitionRegistrar
先緩存起來,先不執行實作了ImportBeanDefinitionRegistrar的方法,在step4完成bean的注冊
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar = ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
普通類
遞歸調用processConfigurationClass方法。
這裡是也對直接實作ImportSelector解析遞歸調用processImports的出口。
this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
//當成配置類進行處理
processConfigurationClass(candidate.asConfigClass(configClass));
解析@ImportResource
用于引入xml形式的bean配置檔案,此步并未真正去解析,隻是先緩存起來,step4完成解析和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);
}
}
解析标注了@Bean的methods
此步隻是通過掃描添加了@Bean注解的方法,封裝成BeanMethod緩存起來,真正的bean解析以及注冊在step4。延遲導入。
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
processInterfaces(configClass, sourceClass);
step4. 完成@Bean、@Import等bean的解析與注冊
經過前一步對配置類的解析,每一個配置類解析後會封裝成ConfigurationClass,這一步針對封裝好的ConfigurationClass繼續完成BeanDefinition的注冊。例如前面解析到的@Bean方法定義的bean、@Import value為ImportBeanDefinitionRegistrar、@ImportedResources指定的bean。
// 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);
ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationClass
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
//省略部分代碼
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
//處理@Bean的beanDefinitoin注冊
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
//處理@ImportedResources的beanDefinitoin注冊
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
//處理@Import下value是ImportBeanDefinitionRegistrar和DeferredImportSelector指定的beanDefinitoin注冊
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
@Bean的解析與注冊
根據@Bean指定的方法,解析注解相關值,構造好BeanDefinition相關屬性,最後通過BeanDefinitionRegistry完成bean的注冊。
ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
//對應的配置類
ConfigurationClass configClass = beanMethod.getConfigurationClass();
//注解資訊
MethodMetadata metadata = beanMethod.getMetadata();
//方法名稱
String methodName = metadata.getMethodName();
//省略部分代碼
//@Bean注解的屬性值
AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
Assert.state(bean != null, "No @Bean annotation attributes");
//擷取bean名稱,如果注解指定了則取指定的名稱,否則取方法名稱
// Consider name and any aliases
List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
String beanName = (!names.isEmpty() ? names.remove(0) : methodName);
//注冊别名
// Register aliases even when overridden
for (String alias : names) {
this.registry.registerAlias(beanName, alias);
}
//省略部分代碼
//開始構造BeanDefinition
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
beanDef.setResource(configClass.getResource());
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
if (metadata.isStatic()) {
//省略部分代碼
}
else {
//設定bean的執行個體化的工廠bean
// instance @Bean method
beanDef.setFactoryBeanName(configClass.getBeanName());
//設定執行個體化的工廠方法
beanDef.setUniqueFactoryMethodName(methodName);
}
if (metadata instanceof StandardMethodMetadata) {
beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod());
}
beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
Autowire autowire = bean.getEnum("autowire");
if (autowire.isAutowire()) {
beanDef.setAutowireMode(autowire.value());
}
boolean autowireCandidate = bean.getBoolean("autowireCandidate");
if (!autowireCandidate) {
beanDef.setAutowireCandidate(false);
}
//指定bean初始化回調的方法
String initMethodName = bean.getString("initMethod");
if (StringUtils.hasText(initMethodName)) {
beanDef.setInitMethodName(initMethodName);
}
//指定bean銷毀時回調的方法
String destroyMethodName = bean.getString("destroyMethod");
beanDef.setDestroyMethodName(destroyMethodName);
// 設定scope
ScopedProxyMode proxyMode = ScopedProxyMode.NO;
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
if (attributes != null) {
beanDef.setScope(attributes.getString("value"));
proxyMode = attributes.getEnum("proxyMode");
if (proxyMode == ScopedProxyMode.DEFAULT) {
proxyMode = ScopedProxyMode.NO;
}
}
//省略部分代碼
//注冊
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}
@ImportedResources的解析與注冊
//不分析
@Import注解value是ImportBeanDefinitionRegistrar
邏輯比較簡單,就是從緩存中拿到前面解析到@Import value是ImportBeanDefinitionRegistrar的所有類,循環調用registerBeanDefinitions,完成自定義BeanDefinition的注冊。
private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
registrars.forEach((registrar, metadata) ->
registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));
}
postProcessBeanFactory
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
if (this.factoriesPostProcessed.contains(factoryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + beanFactory);
}
this.factoriesPostProcessed.add(factoryId);
//如果postProcessBeanDefinitionRegistry沒有執行,則通過這個判斷來調用processConfigBeanDefinitions重新執行。
if (!this.registriesPostProcessed.contains(factoryId)) {
// BeanDefinitionRegistryPostProcessor hook apparently not supported...
// Simply call processConfigurationClasses lazily at this point then.
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
//利用cglib增強@Configuration的bean
enhanceConfigurationClasses(beanFactory);
//添加一個bean後置處理器ImportAwareBeanPostProcessor
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
CGLIB增強Configuration類
問題:為什麼要增強Configuration類?
帶着這個疑問看下enhanceConfigurationClasses方法。
ConfigurationClassPostProcessor#enhanceConfigurationClasses:
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
MethodMetadata methodMetadata = null;
if (beanDef instanceof AnnotatedBeanDefinition) {
methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata();
}
if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
// Configuration class (full or lite) or a configuration-derived @Bean method
// -> resolve bean class at this point...
AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
if (!abd.hasBeanClass()) {
try {
abd.resolveBeanClass(this.beanClassLoader);
}
catch (Throwable ex) {
throw new IllegalStateException(
"Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
}
}
}
//是否是full類型的配置類
if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
//省略部分代碼
//存下來,在下面代碼for循環内進行增強處理
configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
}
}
//沒有full類型的配置類,注解return
if (configBeanDefs.isEmpty()) {
// nothing to enhance -> return immediately
return;
}
//周遊Configuration類,進行增強
ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
AbstractBeanDefinition beanDef = entry.getValue();
// If a @Configuration class gets proxied, always proxy the target class
beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
// Set enhanced subclass of the user-specified bean class
Class<?> configClass = beanDef.getBeanClass();
//增強
Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
if (configClass != enhancedClass) {
beanDef.setBeanClass(enhancedClass);
}
}
}
看enhancer.enhance做了哪些增強:
入口:ConfigurationClassEnhancer#newEnhancer
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(configSuperClass);
//繼承了EnhancedConfiguration接口
enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
enhancer.setUseFactory(false);
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
//添加增強的攔截器
enhancer.setCallbackFilter(CALLBACK_FILTER);
enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
return enhancer;
}
private static final ConditionalCallbackFilter CALLBACK_FILTER = new ConditionalCallbackFilter(CALLBACKS);
//兩個攔截器
// The callbacks to use. Note that these callbacks must be stateless.
private static final Callback[] CALLBACKS = new Callback[] {
new BeanMethodInterceptor(),
new BeanFactoryAwareMethodInterceptor(),
NoOp.INSTANCE
};
EnhancedConfiguration接口繼承了BeanFactoryAware接口,是以增強能使得Configuration類能拿到BeanFactory,這是增強的第一個作用。
增強添加了兩個攔截器,BeanMethodInterceptor和BeanFactoryAwareMethodInterceptor。
BeanMethodInterceptor:攔截@Bean修飾的方法用于,保證隻能被調用一次,確定傳回的bean是單例的,這是增強第二個作用。
BeanFactoryAwareMethodInterceptor:攔截setBeanFactory方法,set $$beanFactory變量值。
添加ImportAwareBeanPostProcessor
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
ImportAwareBeanPostProcessor的作用是在屬性指派的時候,對是EnhancedConfiguration的bean調用setBeanFactory方法(搭配上面會将Configuration類增強為EnhancedConfiguration類來了解)。
總結
- ConfigurationClassPostProcessor利用了BeanDefinitionRegistryPostProcessor能自定義注冊beanDefinition的拓展能力,以及BeanFactoryPostProcessor能對注冊的beanDefinition做修改的拓展能力,進而達到通過注解形式(脫離xml)實作bean的自動注冊。
- 通過在自定義注冊beanDefinition階段,掃描到已經注冊的配置類,取得配置類上相關注解元素(即相關配置),進而完成beanDefinition的添加
- 上一步注冊的beanDefinition可能依然是一個配置類,則需要反複執行上一步的掃描解析注冊過程,直到沒有配置類為止。
- 配置類的定義包括:有@Configuration注解、Component、ComponentScan、Import、ImportResource、方法上有@Bean注解的類,隻要滿足有某一個注解即為配置類。