当我们给一个类加上@Configuration,spring底层到底做了哪些事情?
文章标题3:主要是先有1.spring容器的基本架构 2.spring bean的生命周期 的知识再看下面文章会更好懂。
1.入口
spring核心框架里面一个bean信息注册相关的重要的类:
org.springframework.context.annotation.AnnotatedBeanDefinitionReader
它的作用就是通过他,可以使得BeanDefinitionRegistry的类拥有bean类的编程(注解)式注册的能力。
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
//...省略部分代码
//这个方法就是,将那些注解@Component、@Configuration等的解析能力授予给BeanDefinitionRegistry
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
下面就是registerAnnotationConfigProcessors的源码。
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
//部分源码
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
}
主要就是ConfigurationClassPostProcessor这个类,这个类就让BeanDefinitionRegistry拥有了处理@Configuration的能力。
2.ConfigurationClassPostProcessor分析
1.最关键的方法postProcessBeanDefinitionRegistry,这个方法对BeanDefinitionRegistry 一些事情, 比如说我要这个BeanDefinitionRegistry 拥有对注解了@Configuration的类的注册能力。
postProcessBeanDefinitionRegistry方法的核心代码processConfigBeanDefinitions();
他主要做了:
1.获取每个有加@Configuration 的BeanDefinition
2.设置各种 beanName生成器
3(最核心).解析每个@Configuration class,注解了@Configuration的类到底要干些什么事情
4.将解析完的配置类信息ConfigurationClass,通过 ConfigurationClassBeanDefinitionReader.loadBeanDefinitions (注册中心注册bean定义。)
5.如果之前没有或者上面类定义信息,就将ImportRegistry注册为bean
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
//1.获取每个类有加@Configuration 的BeanDefinition
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
//没有找到一个加@Configuration 的BeanDefinition 直接返回
if (configCandidates.isEmpty()) {
return;
}
//2.对@order的进行排序
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// Detect any custom bean name generation strategy supplied through the enclosing application context
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();
}
// 3.(最核心的)解析每个@Configuration class, 注解了@Configuration的类到底要干些什么事情(下面重点分析)
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
//下面这个就是最最最关键的解析代码
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// 4.将解析完的配置类信息ConfigurationClass,通过 ConfigurationClassBeanDefinitionReader.loadBeanDefinitions (注册中心注册bean定义。)
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
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());
}
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());
// 5.如果之前没有或者类配类定义信息,将ImportRegistry注册为bean以支持
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
//6.清除一些缓存信息
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
3.加了@Configuration的类,到底要做些什么事情
主要做的事情:(下面列出来比较重要的,更完整的流程下更下面补充说明)
1.处理配置类的@PropertySource 注解 : 其实就是将@PropertySource 做了那些事情,记录下来。
2.处理配置类的@ComponentScans 注解。扫描这个包的类, 如果有配置类的, 将他们当成配置类处理。
3.处理@Import 注解 。
4.处理@ImportResource
5.处理注解了@Bean的方法
6.记录他的超类, 主要是防止重新处理等一些操作。
以上就是主要做的事情,但是源码里面要做的还不止于此,还要考虑下面的问题。
1.首先每个配置类里面还可能包含这内部类,所以对每个加了@Component的内部类注册,如果这个内部类也是配置类。那就要执行上面的操作。
2.然后spring考虑到了 这个类的上级的所有超类。所以递归执行上面的需要做的事情,终止条件就是找不到更上级的超类。
3.@Import 注解,循环Import的问题。
比如 AConfiguration @Import 一个 配置类BConfiguration,BConfiguration然后又 通过@Import AConfiguration 会导致 循环Import的问题。 Spring 是通过 ImportStack 一个栈来确定是否有这个循环Import的问题,(处理AConfiguration 之前先判断栈里面是否有处理AConfiguration ,没有就压栈, 有说明循环Import 了)。有的话就抛处CircularImportProblem错误。
整体主要的解析流程:
主要代码再 org.springframework.context.annotation.ConfigurationClassParser#processConfigurationClass
第【1】操作.该类一直到最上面的父类,都进行一下步骤操作(递归的过程)
下面的步骤操作代码主要在:(org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass)
1. 对该类里面的内部类(不包括父类的) 如果是配置类的 全都从第【1】个操作。 相当于递归。
2. 处理配置类的@PropertySource 注解 : 其实就是将@PropertySource 做了那些事情,记录下来。
3. 处理配置类的@ComponentScans 注解。扫描这个包的类, 如果有配置类的, 将他们当成配置类处理,从第【1】个操作处理。
4. 处理@Import 注解 。
5. 处理@ImportResource
6. 处理注解了@Bean的方法
7. 记录他的超类, 主要是防止重新处理等一些操作。
4.关键解析代码
下面列一下关键的代码 从 上面介绍的 processConfigBeanDefinitions 的 parser.parse(candidates);
完整路径如下:
org.springframework.context.annotation.ConfigurationClassParser#parse(java.util.Set<org.springframework.beans.factory.config.BeanDefinitionHolder>)
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
//主要就是parse方法,。
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 (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
this.deferredImportSelectorHandler.process();
}
进去parse();
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
}
进去processConfigurationClass();
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
// Otherwise ignore new imported config class; existing non-imported class overrides it.
return;
}
else {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
// 第【1】操作.该类一直到最上面的父类,都进行一下步骤操作(递归的过程)
SourceClass sourceClass = asSourceClass(configClass, filter);
do {
//进去这个
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
进去doProcessConfigurationClass();
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// a.对该类里面的内部类(不包括父类的) 如果是配置类的 全都从第【1】个操作。 相当于递归。
processMemberClasses(configClass, sourceClass, filter);
}
// 处理配置类的@PropertySource 注解 : 其实就是将@PropertySource 做了那些事情,记录下来。
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
// 处理配置类的@ComponentScans 注解。扫描这个包的类, 如果有配置类的, 将他们当成配置类处理,从第【1】个操作处理。
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// 处理@Import 注解 。
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
//处理@ImportResource
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
// 处理注解了@Bean的方法
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// 处理接口的默认方法
processInterfaces(configClass, sourceClass);
//g.记录他的超类, 主要是防止重新处理等一些操作。
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}
// No superclass -> processing is complete
return null;
}
其实以上源码所做都是为了准备BeanDefinition, 将BeanDefinition注册到BeanDefinitionRegistry。
有问题欢迎留言讨论~~