1.ConfigurationClassPostProcessor
在Spring环境中,我们经常在某个配置类上标注@ComponentScan并指定要扫描的路径,路径下加了@Controller、@Service、@Repositpry、@Component、@Configuration等注解的类会被注册到容器中。如下面的例子:
1.声明配置类和@ComponentScan
java
package org.cosmos.springboot.induction.prop;
@Component
@ComponentScan(value = {"org.cosmos.springboot.induction.prop"})
public class Config {
}
2.声明要加入容器的类
java
package org.cosmos.springboot.induction.prop;
@Repository
public class DemoRepository {
}
@Configuration
public class DemoConfiguration {
}
3.测试类,注释掉@SpringBootApplication和SpringApplication的run方法,Spring Boot环境没启动,直接用Spring环境:
java
package org.cosmos.springboot.induction.prop;
//@SpringBootApplication
public class PropSpringApplication {
public static void main(String[] args) {
//ConfigurableApplicationContext ctx = SpringApplication.run(PropSpringApplication.class, args);
ApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class,DemoConfiguration.class);
Stream.of(ctx.getBeanDefinitionNames()).forEach(System.out::println);
}
}
结果:
AnnotationConfigApplicationContext有一个有参构造器,可以传入指定类,它先调无参构造初始化读取器和扫描器,然后注册传入的类,最后再刷新容器。
java
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
private final AnnotatedBeanDefinitionReader reader;
private final ClassPathBeanDefinitionScanner scanner;
//...
//无参构造
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
//构造器指定要注册的类
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();//先调无参构造
register(componentClasses);
refresh();
}
@Override
public void register(Class<?>... componentClasses) {
Assert.notEmpty(componentClasses, "At least one component class must be specified");
this.reader.register(componentClasses);
}
//...
}
注册类是用BeanDefinitionRegistry的registerBeanDefinition方法;刷新容器会调AbstractApplicationContext的refresh方法,这正是我们之前分析过的IOC容器刷新的地方。当时我们说了这个方法的invokeBeanFactoryPostProcessors阶段,即调用beanFactory的所有后置处理器阶段,有一个BeanDefinitionRegistryPostProcessor会处理配置类的解析和注册工作:ConfigurationClassPostProcessor。今天我们就分析一家这个后置处理器。
如果把这个案例中的@SpringBootApplication和SpringApplication的run方法的注释放开,启动Spring Boot环境,在run方法中也会刷新IOC容器,同样会调用ConfigurationClassPostProcessor处理所有配置类。
ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor ,而BeanDefinitionRegistryPostProcessor 继承了BeanFactoryPostProcessor ,按照之前分析过的容器刷新流程,ConfigurationClassPostProcessor 会先执行postProcessBeanDefinitionRegistry,再处理postProcessBeanFactory方法。
2. postProcessBeanDefinitionRegistry
ConfigurationClassPostProcessor先执行postProcessBeanDefinitionRegistry:
java
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
// throw ...
}
if (this.factoriesPostProcessed.contains(registryId)) {
// throw new ...
}
this.registriesPostProcessed.add(registryId);
processConfigBeanDefinitions(registry);
}
重点在最后一行processConfigBeanDefinitions,它会过滤出所有配置类,然后循环解析每个配置类并注册配置类的bean定义。总览processConfigBeanDefinitions源码:
java
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
//从BeanDefinitionRegistry中取注册的全部bean名
//上面案例通过AnnotationConfigApplicationContext构造器手动注册
//Spring Boot主启动类会把自己注册,后面配合@SpringBootApplication会把开发者标注@Component等的类注册到容器
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
//logger...
}
//checkConfigurationClassCandidate判断一个类是否配置类,并为BeanDefinition设置属性lite或full
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
if (configCandidates.isEmpty()) {
return;
}
// 排序
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// beanName生成器
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
// 创建ConfigurationClassParser
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 {
//配置类解析,在此处会解析配置类上的注解(ComponentScan扫描出的类,@Import注册的类,以及@Bean方法定义的类)
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// ConfigurationClassBeanDefinitionReader
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
//Bean定义注册
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
// 判断reader.loadBeanDefinitions(configClasses)有没有添加新的anDefinition
// 若有,则nDefinitionCount()大于candidateNames.length
//则需要把新加入的还没有被解析过的bean重新加入到candidates变量中,重新执行一遍配置类解析和Bean定义注册
if (registry.getBeanDefinitionCount() > candidateNames.length) {
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());
}
// 未解析的类添加到candidates中,就会进入到下一次的while的循环
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));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
//...
}
processConfigBeanDefinitions先获取所有候选配置类并判断,获得所有配置类后再循环解析和注册bean定义。
2.1 获取候选配置类
先通过BeanDefinitionRegistry获取注册的所有bean定义名。
Spring环境中,上面案例的Config和DemoConfiguration在AnnotationConfigApplicationContext构造器中通过BeanDefinitionRegistry注册了。而在Spring Boot中,Config和DemoConfiguration不会先注册,而是通过主启动类注册它们。主启动类执行run方法到prepareContext阶段时也会通过BeanDefinitionRegistry注册自己:
所以processConfigBeanDefinitions会获取到主启动类,把他当作候选配置类。而主启动类的@SpringBootApplication是由@Configuration、@ComponentScan、@EnableAutoConfiguration着3个复合的,所以主启动类是配置类,它会通过下面的配置类判断条件。
2.2 判断候选配置类
checkConfigurationClassCandidate方法判断一个类是否配置类,并为BeanDefinition设置属性lite或full。Spring 文档说明了@Configuration的lite模式或和full模式。简单说就是@Bean方法的返回值会注入到容器中,如果@Bean方法所在的类被@Configuration标注,就是full模式,这种模式会给配置类通过CGLIB生成一个代理,所有@Bean标注的方法都是通过代理进行的;如果@Bean方法所在类被@Configuration以外注解如@Component标注,或被Configuration标注,但它的属性proxyBeanMethods是false,就是lite模式,这种模式不会生成代理,某个@Bean方法中如果需要其他@Bean方法返回的对象,就要从容器中取出一个新对象了。
java
abstract class ConfigurationClassUtils {
public static final String CONFIGURATION_CLASS_FULL = "full";
public static final String CONFIGURATION_CLASS_LITE = "lite";
public static final String CONFIGURATION_CLASS_ATTRIBUTE =
Conventions.getQualifiedAttributeName(ConfigurationClassPostProcessor.class, "configurationClass");
public static boolean checkConfigurationClassCandidate(
BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
//...
AnnotationMetadata metadata;
// if ...else if...else
Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
//full模式:没@Configuration 或 有@Configuration,但proxyBeanMethods属性是false
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
//lite模式:含有@Bean,@Component,@ComponentScan,@Import,@ImportResource
else if (config != null || isConfigurationCandidate(metadata)) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
else {
return false;
}
//...
return true;
}
//ConfigurationClassUtils的属性
private static final Set<String> candidateIndicators = new HashSet<>(8);
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) {
// 不处理接口
if (metadata.isInterface()) {
return false;
}
// 几个经典注解
for (String indicator : candidateIndicators) {
if (metadata.isAnnotated(indicator)) {
return true;
}
}
// 判断是否有@Bean
return hasBeanMethods(metadata);
}
static boolean hasBeanMethods(AnnotationMetadata metadata) {
try {
return metadata.hasAnnotatedMethods(Bean.class.getName());
}
//catch...
}
}
2.2 配置类解析
ConfigurationClassParser的parse分两步,重载的parse方法解析配置类、解析DeferredImportSelector指定的类:
java
class ConfigurationClassParser {
//...
private final DeferredImportSelectorHandler deferredImportSelectorHandler = new DeferredImportSelectorHandler();
public void parse(Set<BeanDefinitionHolder> configCandidates) {
//1.解析配置类
// 根据Bean定义类型,调用的重载方法parse
// 最终都是调用processConfigurationClass方法
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
// catch ...
}
//2.解析DeferredImportSelector指定的类
this.deferredImportSelectorHandler.process();
}
}
重载的parse方法会解析配置类上的注解(@ComponentScan,@Import,@Bean等等),解析完以后把结果放入到parse的缓存configurationClasses中去。每个重载的parse方法,如下面的,先把入参封装成ConfigurationClass,然后调processConfigurationClass。
java
protected final void parse(Class<?> clazz, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(clazz, beanName), DEFAULT_EXCLUSION_FILTER);
}
ConfigurationClass是配置类的一种模型,为了解析配置类上加的注解,它设计了几种属性:
java
final class ConfigurationClass {
private final AnnotationMetadata metadata;
private final Resource resource;
@Nullable
private String beanName;
private final Set<ConfigurationClass> importedBy = new LinkedHashSet<>(1); //@Import相关
private final Set<BeanMethod> beanMethods = new LinkedHashSet<>(); //@Bean
private final Map<String, Class<? extends BeanDefinitionReader>> importedResources =
new LinkedHashMap<>(); //@ImportResource相关
private final Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars =
new LinkedHashMap<>(); //@Import导入的ImportBeanDefinitionRegistrar
final Set<String> skippedBeanMethods = new HashSet<>();
//...
}
2.2.1 processConfigurationClass
每个配置类的解析都会执行processConfigurationClass,解析完放到缓存configurationClasses中。配置类如果有父类,就循环解析。其中SourceClass是对ConfigClass这个模型的简单包装,是为了以统一的方式处理配置类,而不管它是如何加载。
java
//缓存
private final Map<ConfigurationClass, ConfigurationClass> configurationClasses = new LinkedHashMap<>();
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
//@Condition注解判断逻辑
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
//...
}
//配置类可能有父类,循环处理,doProcessConfigurationClass会返回父类
SourceClass sourceClass = asSourceClass(configClass, filter);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);
//放回缓存
this.configurationClasses.put(configClass, configClass);
}
2.2.2 doProcessConfigurationClass
doXXX一般是做具体工作的,会完成XXX交待的任务。这里doProcessConfigurationClass是真正干活的,它具体做了下面8种处理:
(1) 处理配置类的内部类。
(2) 处理配置类上@PropertySource注解。
(3) 解析配置类的@ComponentScan和@ComponentScans注解,然后根据这2种注解配置的包扫描路径,利用ASM技术扫描出所有需要注入的类。如果扫描出的类也加了@ComponentScan和@ComponentScans,就递归扫描,直到所有加了这两个注解的类都被解析。
(4) 处理@Import注解,具体有三种解析方式。
(5) 处理@ImportResource注解。
(6) 处理配置类中标注@Bean的方法。
(7) 处理接口默认方法加@Bean的情况。
(8) 解析配置类的父类。
java
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {
//(1)@Component标注的类的内部类是否也是配置类
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
//配置类的内部类也是配置类,就递归处理
processMemberClasses(configClass, sourceClass, filter);
}
//(2)处理加了@PropertySource的配置类
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
//else ...
}
//(3)处理@ComponentScan或者@ComponentScans注解
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) {
//@ComponentScan和@ComponentScans指明的的扫描的包里面的类
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// 扫面出来的bean如果也有这2种注解,用parse递归解析
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());
}
}
}
}
//(4)处理@Import注解
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
//(5)处理@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) {
//解析出locations属性指定的文件
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
//(6)处理@Bean标注的方法
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
//(7)处理接口默认方法加@Bean
//JDK8,接口有默认方法,默认方法有@Bean的处理
processInterfaces(configClass, sourceClass);
//(8)解析父类
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();
}
}
//没有父类返回null
return null;
}
重点看下面几种情况的处理:
- 处理配置类的内部类
同样也用工具类的isConfigurationCandidate方法判断内部类是否是配置类,如果是,就用processConfigurationClass方法递归解析。
java
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) {
//也是用工具类的isConfigurationCandidate方法判断
if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
candidates.add(memberClass);
}
}
OrderComparator.sort(candidates);
for (SourceClass candidate : candidates) {
//if ...
else {
try {
//内部内满足上面的条件,递归解析
processConfigurationClass(candidate.asConfigClass(configClass), filter);
} //finally...
}
}
}
}
2.处理@ComponentScan或者@ComponentScans注解
先获取这2种注解并读取注解种配置的包扫描路径,然后获取包路径下的bean,如果扫描出的bean如果也有这2种注解,用parse递归解析。
ConfigurationClassPostProcessor组合了ComponentScanAnnotationParser,看下ComponentScanAnnotationParser的parse:
java
class ComponentScanAnnotationParser {
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
//创建类路径Bean定义扫描器
//获取@componentScan的scopedProxy属性并设置到扫描器
//设置resourcePattern到扫描器
//设置includeFilters和excludeFilters到扫描器
//设置lazyInit到扫描器
//获取扫描的包路径
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));
}
//添加排除过滤器
//扫描
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
}
debug观察,ComponentScanAnnotationParser的parse方法,会把主启动类所在包作为basePackages,进而传给doScan方法:
真正干活的还是doScan:
java
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
//...
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
//遍历每个包路径
for (String basePackage : basePackages) {
//!!!重要方法
//读取包路径下的资源,并解析出该包下所有符合条件的类生成bd.
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
//遍历包路径下符合条件的类的bean定义
for (BeanDefinition candidate : candidates) {
//解析类的ScopeMetadata
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
//生成类名
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
//根据类型处理bean定义
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
//检测bean定义是否需要被注册或是否与已有bean定义冲突
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
//用applyScopedProxyMode方法生成代理域对象的bean定义
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
}
findCandidateComponents方法很重要,它会获取指定包路径下所有bean定义:
java
public class ClassPathScanningCandidateComponentProvider implements EnvironmentCapable, ResourceLoaderAware {
static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
//获取指定包路径下所有bean定义
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
//if ...
else {
return scanCandidateComponents(basePackage);
}
}
//findCandidateComponents进一步调用
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
//拼出完整扫描路径
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
//通过路径获取Resource
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
for (Resource resource : resources) {
if (resource.isReadable()) {
try {
//从每个Resource创建BeanDefinition
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {
candidates.add(sbd);
}
}
}
}
}
return candidates;
}
}
}
debug看出来完整扫描路径:
果真把这个位置下的所有加了@Component @Configuration的类扫描出来了,所以前面案例中Config和DemoConfiguration是通过主启动类注册到容器中的,就体现在这里。
-
处理@Import注解@Import可以导入普通类、配置类、ImportSelector实现类、ImportBeanDefinitionRegistrar实现类,这里分三种的情况处理:
java
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
boolean checkForCircularImports) {
//获取的所有@Import导入的所有类
if (importCandidates.isEmpty()) {
return;
}
//...
//@Import导入的类分成3类
for (SourceClass candidate : importCandidates) {
//1. 导入了ImportSelector
if (candidate.isAssignable(ImportSelector.class)) {
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);
}
//1.1 特殊的ImportSelector:DeferredImportSelector
if (selector instanceof DeferredImportSelector) {
//委派给ConfigurationClassPostProcessor的deferredImportSelectorHandler属性来处理
//实际上就是存储起来, 暂时不调用
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
//1.2 普通的ImportSelector
//这种ImportSelector的selectImports会指定要导入的类,包括普通类、配置类、ImportSelector类和
//ImportBeanDefinitionRegistrar类
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
//递归处理
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
}
//2. 导入了ImportBeanDefinitionRegistrar
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
Class<?> candidateClass = candidate.loadClass();
//反射创建这个ImportBeanDefinitionRegistrar
ImportBeanDefinitionRegistrar registrar =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
//这个ImportBeanDefinitionRegistrar对象放入到ConfigClass模型中
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
//3.导入了其他类
//构建这个被导类的ConfigurationClass模型,它的importedBy属性就是当前要解析的@Import标注的配置类
//递归解析这个被导类
processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
}
}
导入了ImportSelector类,也分DeferredImportSelector类和其他ImportSelector类。DeferredImportSelector类会委托ConfigurationClassPostProcessor组合的DeferredImportSelectorHandler处理,其实就把DeferredImportSelector类和配置类包装一下,留到重载parse方法处理完后统一解析;其他ImportSelector类,会进行递归处理。
导入了ImportBeanDefinitionRegistrar类,会反射创建这个ImportBeanDefinitionRegistrar对象,然后把它加入到配置类的模型ConfigurationClass的importBeanDefinitionRegistrars属性中。
导入了其他类,包括普通类和配置类,都会构建它的ConfigurationClass模型,然后递归调用processConfigurationClass。这些类如果有父类,在processConfigurationClass中会循环解析所有类,直到没有父类为止。
前面的案例中,我们加几个类,然后分析加了@Import注解的配置类解析到这一步的情况。
声明普通类
java
package org.cosmos.springboot.induction.prop;
public class Demo {
}
声明ImportSelector类及其指定类
java
package org.cosmos.springboot.induction.prop;
public class SelectorVO {
}
public class DemoImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{SelectorVO.class.getName()};
}
}
声明ImportBeanDefinitionRegistrar类及其指定类
java
package org.cosmos.springboot.induction.prop;
public class RegistrarVO {
}
public class DemoRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry){
registry.registerBeanDefinition("Registrar", new RootBeanDefinition(RegistrarVO.class));
}
}
声明DeferredImportSelector类及其指定类
java
package org.cosmos.springboot.induction.prop;
public class DeferredVO {
}
public class DemoDeferredImportSelector implements DeferredImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{DeferredVO.class.getName()};
}
}
配置类加@Import,分别导入普通类、ImportSelector类、ImportBeanDefinitionRegistrar类和DeferredImportSelector类:
java
package org.cosmos.springboot.induction.prop;
@Configuration
@Import({
Demo.class,
DemoImportSelector.class,
DemoRegistrar.class,
DemoDeferredImportSelector.class,
})
public class DemoConfiguration {
}
执行到配置类DemoConfiguration对应processImports:
@Import对应的4种类都被收集到了,普通类Demo会被当作第3种情况处理,
普通类果真会构建出配置类模型:
其他几种情况类似。
2.2.3 延迟解析
DeferredImportSelector的处理时机晚于ImportSelector,适合在导入一些类后补充导入其他类,我们分析一下ConfigurationClassPostProcessor是如何通过它来实现延迟导入一些配置类的。
processImports方法中处理被@Import导入的DeferredImportSelector时,会用DeferredImportSelectorHandler的handle方法暂存一下它。handle方法先把要处理的DeferredImportSelector包装成一个DeferredImportSelectorHolder对象holder,这个holder是一个容器,保存了配置类模型ConfigurationClass和要处理的DeferredImportSelector。同时DeferredImportSelectorHandler组合了一个holder集合deferredImportSelectors,这个集合被初始化了,所以handle方法会执行else,把要处理的holder加进deferredImportSelectors。
java
private class DeferredImportSelectorHandler {
@Nullable
private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();
public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
//deferredImportSelectors已被初始化,所以会走else分支,将holder暂存
if (this.deferredImportSelectors == null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
handler.register(holder);
handler.processGroupImports();
}
else {
this.deferredImportSelectors.add(holder);
}
}
//process方法...
}
反过来看DeferredImportSelectorHandler,它有handle和process这2个方法。重载parse方法解析配置类,执行processImports方法时会用handle方法暂存DeferredImportSelector;等到重载parse方法完毕,就会用process方法统一处理所有导入的DeferredImportSelector:
java
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
//重载parse...
}
//处理所有DeferredImportSelector
this.deferredImportSelectorHandler.process();
}
Spring Boot主启动类上@SpringBootApplication注解由@EnableAutoConfiguration等3个注解复合,而@EnableAutoConfiguration又由@AutoConfigurationPackage和@Import({AutoConfigurationImportSelector.class})复合,进一步,@AutoConfigurationPackage又由@Import({AutoConfigurationPackages.RegistrarRegistrar.class})标注,所以主启动类作为配置类,加了@Import注解,导入了AutoConfigurationPackages.RegistrarRegistrar和AutoConfigurationImportSelector。AutoConfigurationImportSelector是DeferredImportSelector,所以在这里统一延迟解析所有自动装配的类。
java
private class DeferredImportSelectorHandler {
@Nullable
private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();
//handle方法...
public void process() {
//临时变量,暂存要处理所有的DeferredImportSelector包装对象
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
try {
if (deferredImports != null) {
//创建分组处理器handler
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
//1.用handler注册DeferredImportSelector,
//实际是添加到DeferredImportSelectorGrouping这个新的分组对象
deferredImports.forEach(handler::register);
//2.用handler真正处理分组内的所有DeferredImportSelector
handler.processGroupImports();
}
}
finally {
this.deferredImportSelectors = new ArrayList<>();
}
}
}
deferredImportSelectors非空,添加的正是AutoConfigurationImportSelector的包装对象,所以DeferredImportSelectorHandler执行process会先创建DeferredImportSelectorGroupingHandler对象handler,然后用这个hander分别注册所有包装对象holder,然后用hander的processGroupImports真正解析出所有要注册进容器的bean。
下面分析DeferredImportSelectorGroupingHandler。
之前说过,DeferredImportSelector接口实现ImportSelector的同时,又设计了一个内部接口Group,为了把不同的DeferredImportSelector实现类根据一些条件分成不同的组,就抽象出这个接口。DeferredImportSelector的默认方法getImportGroup会返回要处理的Group。而Group里的process是导入所有配置类的入口,内部类Entry是需要导入的类的抽象,selectImports会返回这个Group内所有的Entry。Group是重中之重!每个DeferredImportSelector有一个组Group,每个Group里面包含要处理的DeferredImportSelector。
DeferredImportSelectorGroupingHandler就是处理分组的,它有2个属性groupings和configurationClasses。groupings是一个Map,保存分组和新分组对象DeferredImportSelectorGrouping;configurationClasses也是Map,保存了配置类,我们的案例中Spring Boot主启动类和配置类DemoConfiguration都会保存在configurationClasses。
DeferredImportSelectorGroupingHandler执行register处理DeferredImportSelectorHolder,先获取组group,然后通过Map的computeIfAbsent,用这个组创建了一个新的分组对象DeferredImportSelectorGrouping,最后把组group做key,新分组对象做value,放到groupings中。就是把DeferredImportSelector的分组包装一下,供后面的processGroupImports使用,真正干活的还是被包装分组的process等方法。
java
private class DeferredImportSelectorGroupingHandler {
private final Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>();
private final Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap<>();
//把DeferredImportSelector包装对象注册到组中
public void register(DeferredImportSelectorHolder deferredImport) {
//通过DeferredImportSelector的getImportGroup获取组group
Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
//group存在就使用,不存在就用DeferredImportSelector包装对象
//从grouping中取key是group的value,取到就返回,没取到就用group来创建DeferredImportSelectorGrouping对象
//然后把group做key,DeferredImportSelectorGrouping对象做value,放回到groupings,并返回这个value
DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
(group != null ? group : deferredImport),
key -> new DeferredImportSelectorGrouping(createGroup(group)));
//新分组对象组合了组内所有DeferredImportSelector包装对象
//直接添加groupings
grouping.add(deferredImport);
//保存标注了@Impor({xxxDeferredImportSelector.class})的配置类
this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getConfigurationClass());
}
//真正解析出所有要注册进容器的bean:processGroupImports...
}
debug看出,Spring Boot的AutoConfigurationImportSelector.AutoConfigurationGroup确实被包装了一下:
我们的案例中处理DemoDeferredImportSelector时,也包装了一个新组对像DeferredImportSelectorGrouping:
DeferredImportSelectorGrouping是对Group的又一层封装,组合了Group和对应要处理的所有DeferredImportSelectorHolder。
java
private static class DeferredImportSelectorGrouping {
//分组Group
private final DeferredImportSelector.Group group;
//分组要处理的所有DeferredImportSelectorHolder
private final List<DeferredImportSelectorHolder> deferredImports = new ArrayList<>();
DeferredImportSelectorGrouping(Group group) {
this.group = group;
}
public void add(DeferredImportSelectorHolder deferredImport) {
//直接添加进deferredImports
this.deferredImports.add(deferredImport);
}
public Iterable<Group.Entry> getImports() {
for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
//核心!!!
//分组内每一个DeferredImportSelector的process方法都调用!!!
//而每个DeferredImportSelector都指定一些类将来要注册到容器中
//所以这里会把所有延迟解析的类解析出来,为了后面注册到容器中准备
this.group.process(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getImportSelector());
}
//用group的selectImports,返回分组内的所有解析出来的bean
return this.group.selectImports();
}
//获取过滤器
public Predicate<String> getCandidateFilter() {
Predicate<String> mergedFilter = DEFAULT_EXCLUSION_FILTER;
for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
//Spring Boot自动装配就3个过滤器:OnBeanCondition,OnClassCondition,OnWebApplicationCondition
//META-INF/spring-autoconfigure-metadata.properties 作为这几个过滤器的metadata
Predicate<String> selectorFilter = deferredImport.getImportSelector().getExclusionFilter();
if (selectorFilter != null) {
mergedFilter = mergedFilter.or(selectorFilter);
}
}
return mergedFilter;
}
}
DeferredImportSelectorGroupingHandler执行processGroupImports解析所有要注册到容器的bean:
java
private class DeferredImportSelectorGroupingHandler {
private final Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>();
private final Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap<>();
//register: 把DeferredImportSelector包装对象注册到组中...
//真正解析的地方, 关键是
public void processGroupImports() {
//遍历groupings
for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
//获取排除过滤器
Predicate<String> exclusionFilter = grouping.getCandidateFilter();
//grouping.getImports(): 获取每个分组解析出来的bean,这些bean后面要被注册进容器
grouping.getImports().forEach(entry -> {
//configurationClass:Spring Boot主启动类或其他配置类
ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
try {
//被解析出来的bean还会执行一次processImports
processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),
Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),
exclusionFilter, false);
}
//catch...
});
}
}
}
总结一下:
-
DeferredImportSelector会指定将要注册到容器中bean,它指定的bean会比ImportSelector等要晚点注册。
-
重载parse方法会用DeferredImportSelectorHandler暂存所有DeferredImportSelector
-
然后用DeferredImportSelectorHandler的process方法处理所有暂存的DeferredImportSelector
-
DeferredImportSelectorHandler会把工作委托给DeferredImportSelectorGroupingHandler
-
DeferredImportSelectorGroupingHandler有分组处理的概念,有2个方法register和processGroupImports
-
register:创建若干分组对象DeferredImportSelectorGrouping并保存配置类 。
DeferredImportSelectorGrouping对应一个组(Spring Boot主启动类默认分组AutoConfigurationImportSelector.AutoConfigurationGroup,或者其他分组),会调用这个组的process方法完成解
- processGroupImports:遍历所有分组对象DeferredImportSelectorGrouping,每一个分组对象解析出所有将要注册到容器的bean,每一个bean还会进行一次解析@Import注解动作。
一幅图来直观看下这里的细节:
配置类解析完了,各种配置类都封装在ConfigurationClass集合了:
2.3 Bean定义注册
ConfigurationClassBeanDefinitionReader的loadBeanDefinitions方法会把上面解析出来的ConfigClass数据转换成BeanDefinition,最后通过BeanDefinitionRegistry注册。具体会处理@Import导入类指定的类、@Bean标注的配置类、@ImporteResource标注的配置类和@Import导入的ImportBeanDefinitionRegistrar指定的类
java
class ConfigurationClassBeanDefinitionReader {
//...
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
//trackedConditionEvaluator是@Condition相关
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
for (ConfigurationClass configClass : configurationModel) {
//分别注册Bean定义
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
//如果@Condition系列注解指明不能注册,就从注册器移除
if (trackedConditionEvaluator.shouldSkip(configClass)) {
String beanName = configClass.getBeanName();
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
this.registry.removeBeanDefinition(beanName);
}
this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
return;
}
//注册@Import导入类指定的类
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
//@Bean标注的配置类
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
//@ImporteResource标注的配置类
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
//注册@Import导入的ImportBeanDefinitionRegistrar指定的类
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
}
2.3.1 @Import导入类指定的类
debug发现
源码处理情况:
java
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
AnnotationMetadata metadata = configClass.getMetadata();
//创建BeanDefinition
AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
//处理被导入配置类的域代理,bean名
ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
configBeanDef.setScope(scopeMetadata.getScopeName());
String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
//创建代理对象的情况
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
//注册
this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
configClass.setBeanName(configBeanName);
}
结果确实这样:
DemoImportSelector指定的SelectVo、DemoDeferredImportSelector指定的DeferredVO也会在这里注册。
2.3.2 @Bean标注的配置类
java
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
ConfigurationClass configClass = beanMethod.getConfigurationClass();
MethodMetadata metadata = beanMethod.getMetadata();
String methodName = metadata.getMethodName();
//处理@Condition
AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
//处理@Bean的name属性和@Bean创建了类的是否被覆盖
//创建配置类的BeanDefinition
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata, beanName);
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
if (metadata.isStatic()) {
// 静态 @Bean方法
if (configClass.getMetadata() instanceof StandardAnnotationMetadata) {
beanDef.setBeanClass(((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass());
}
else {
beanDef.setBeanClassName(configClass.getMetadata().getClassName());
}
beanDef.setUniqueFactoryMethodName(methodName);
}
else {
beanDef.setFactoryBeanName(configClass.getBeanName());
beanDef.setUniqueFactoryMethodName(methodName);
}
if (metadata instanceof StandardMethodMetadata) {
beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod());
}
//设置BeanDefinition的autowire,initMethod,域等属性
beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
//...
// 如果配置类有代理对象创建,创建代理对象的BeanDefinition
BeanDefinition beanDefToRegister = beanDef;
if (proxyMode != ScopedProxyMode.NO) {
BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
new BeanDefinitionHolder(beanDef, beanName), this.registry,
proxyMode == ScopedProxyMode.TARGET_CLASS);
beanDefToRegister = new ConfigurationClassBeanDefinition(
(RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata, beanName);
}
//注册
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}
@ImporteResource标注的配置类没什么可说的,最后是通过BeanDefinitionReader注册了BeanDefinition,最终也是通过BeanDefinitionRegistry注册的。
2.3.3 @Import导入的ImportBeanDefinitionRegistrar
java
private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
registrars.forEach((registrar, metadata) ->
registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));
}
配置类解析时赋值给ConfigurationClass的属性中importBeanDefinitionRegistrars了,这里直接取出来具体的ImportBeanDefinitionRegistrar类并调它的注册方法。
3. postProcessBeanFactory
ConfigurationClassPostProcessor执行完postProcessBeanDefinitionRegistry后,再处理postProcessBeanFactory方法。主要做了2件事,通过Cglib动态代理增强配置类、向beanFactory添加一个后置处理器ImportAwareBeanPostProcessor。
java
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
if (this.factoriesPostProcessed.contains(factoryId)) {
// throw ...
}
this.factoriesPostProcessed.add(factoryId);
//先执行postProcessorBeanDefinitionRegistry方法时,会调用processConfigBeanDefinitions方法
//为了避免重复执行,在执行方法之前会先生成一个id放入到一个set
//每次执行之前先判断id是否存在,在此处永远不会进入到if语句中
if (!this.registriesPostProcessed.contains(factoryId)) {
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
//1.Cglib动态代理增强配置类
enhanceConfigurationClasses(beanFactory);
//2.向beanFactory添加ImportAwareBeanPostProcessor
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
3.1 Cglib动态代理增强配置类
前面说到配置类有full模式和lite模式,full模式的配置类会生成配置类的代理对象,这里采用的是Cglib子类动态代理方法。
java
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
//获取所有的BeanDefinitionName然后遍历
for (String beanName : beanFactory.getBeanDefinitionNames()) {
//获取BeanDefinition
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
AnnotationMetadata annotationMetadata = null;
MethodMetadata methodMetadata = null;
//元数据的一些处理...
//full模式
if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
//if...else...
//full模式的配置类添加到configBeanDefs
configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
}
}
if (configBeanDefs.isEmpty()) {
//没有full模式配置类,不增强
return;
}
//创建配置类增强器enhancer
ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
AbstractBeanDefinition beanDef = entry.getValue();
beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
Class<?> configClass = beanDef.getBeanClass();
//增强
Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
if (configClass != enhancedClass) {
//把代理设置回BeanDefinition
beanDef.setBeanClass(enhancedClass);
}
}
}
重点在于ConfigurationClassEnhancer的enhance方法,这个方法通过newEnhancer创建了Spring包装的Cglib增强器,并让这个增强器实现EnhancedConfiguration接口和添加了2个MethodInterceptor。EnhancedConfiguration实现了BeanFactoryAware,而添加的BeanFactoryAwareMethodInterceptor,它的拦截方法会拦截BeanFactoryAware的setBeanFactory调用,所以会拦截增强类的setBeanFactory调用。
java
class ConfigurationClassEnhancer {
private static final Callback[] CALLBACKS = new Callback[] {
//拦截@Bean方法的调用
new BeanMethodInterceptor(),
//拦截BeanFactoryAware的setBeanFactory调用
new BeanFactoryAwareMethodInterceptor(),
NoOp.INSTANCE
};
private static final ConditionalCallbackFilter CALLBACK_FILTER = new ConditionalCallbackFilter(CALLBACKS);
public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
//已被增强就返回
return configClass;
}
Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
return enhancedClass;
}
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
//Spring重新打包了CGLIB
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(configSuperClass);
//配置类的Cglib代理对象要实现EnhancedConfiguration
//EnhancedConfiguration实现了BeanFactoryAware
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;
}
}
3.2 添加ImportAwareBeanPostProcessor
向beanFactory添加ImportAwareBeanPostProcessor后,在后面刷新IOC容器时会触发这个后置处理器的调用。postProcessProperties会为被CGLIB增强时实现了EnhancedConfiguration接口的代理类,设置beanFactory属性。postProcessBeforeInitialization是处理ImportAware相关。
java
private static class ImportAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
private final BeanFactory beanFactory;
public ImportAwareBeanPostProcessor(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public PropertyValues postProcessProperties(@Nullable PropertyValues pvs, Object bean, String beanName) {
//若bean实现了EnhancedConfiguration,则为它的beanFactory属性赋值
if (bean instanceof EnhancedConfiguration) {
((EnhancedConfiguration) bean).setBeanFactory(this.beanFactory);
}
return pvs;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
if (bean instanceof ImportAware) {
ImportRegistry ir = this.beanFactory.getBean(IMPORT_REGISTRY_BEAN_NAME, ImportRegistry.class);
AnnotationMetadata importingClass = ir.getImportingClassFor(ClassUtils.getUserClass(bean).getName());
if (importingClass != null) {
((ImportAware) bean).setImportMetadata(importingClass);
}
}
return bean;
}
}