Spring Boot 源码分析(六):配置类解析和注册-ConfigurationClassPostProcessor

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;
	}

重点看下面几种情况的处理:

  1. 处理配置类的内部类

同样也用工具类的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是通过主启动类注册到容器中的,就体现在这里。

  1. 处理@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;
		}
	}
相关推荐
❥ღ Komo·23 分钟前
K8s服务发现与DNS解析全解析
java·开发语言
g***B7382 小时前
Java 工程复杂性的真正来源:从语言设计到现代架构的全链路解析
java·人工智能·架构
期待のcode4 小时前
MyBatisX插件
java·数据库·后端·mybatis·springboot
醇氧7 小时前
【Windows】优雅启动:解析一个 Java 服务的后台启动脚本
java·开发语言·windows
sunxunyong7 小时前
doris运维命令
java·运维·数据库
菜鸟起航ing7 小时前
Spring AI 全方位指南:从基础入门到高级实战
java·人工智能·spring
古城小栈7 小时前
Docker 多阶段构建:Go_Java 镜像瘦身运动
java·docker·golang
华仔啊7 小时前
这 10 个 MySQL 高级用法,让你的代码又快又好看
后端·mysql
MapGIS技术支持7 小时前
MapGIS Objects Java计算一个三维点到平面的距离
java·开发语言·平面·制图·mapgis
Coder_Boy_8 小时前
业务导向型技术日志首日记录(业务中使用的技术栈)
java·驱动开发·微服务