前言
使用@Configuration注解标注配置类,大家已经驾轻就熟了,但spring对Configuration配置类的解析是怎样的,其中又涉及哪些关键点和值得探究的地方,下面主要对这些疑点进行分析;
首先分析下ConfigurationClassPostProcessor
,该类主要完成@Configuration类的处理
一、ConfigurationClassPostProcessor的注册时机
从SpringIOC - BeanFactory浅析一文中可以知道ConfigurationClassPostProcessor
注册时机是初始化容器过程中,代码如下
public AnnotationConfigApplicationContext() {
//对DefaultListableBeanFactory进行初始化
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
new AnnotatedBeanDefinitionReader(this)
底层使用了registerAnnotationConfigProcessors
方法
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors( BeanDefinitionRegistry registry, @Nullable Object source) {
//获取对象
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
//忽略代码.........
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
/**********************************检查有没有,如果没有注册*************************/
//org.springframework.context.annotation.internalConfigurationAnnotationProcessor。
//@Configuration注解处理器
//ConfigurationClassPostProcessor是一个BeanFactoryPostProcessor(BeanDefinitionRegistryPostProcessor)
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
信息,把他封装成BeanDefinition
对象注册到BeanFactory的BeanDefinition池中
二、ConfigurationClassPostProcessor的调用时机
从上图可以看出ConfigurationClassPostProcessor
是一个BeanFactoryPostProcessor
,BeanDefinitionRegistry
,所以这个类会在refresh方法中invokeBeanFactoryPostProcessors(beanFactory)
执行,其底层如下
public static void invokeBeanFactoryPostProcessors( ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
//只有此beanFactory 是BeanDefinitionRegistry 才能执行BeanDefinitionRegistryPostProcessor,才能修改Bean的定义嘛~
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
//忽略代码。。。。。。。。
// 先执行实现了PriorityOrdered接口的,然后是Ordered接口的,最后执行剩下的
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// 先从容器中拿出来所有的BeanDefinitionRegistryPostProcessor的名字
// 本例中有一个这个类型的处理器:ConfigurationClassPostProcessor(显然是处理@Configuration这种Bean的)
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
// 实例化取到的BeanDefinitionRegistryPostProcessor,并且把他放到单利池中
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
// 排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
// 此处缓冲起来(需要注意的是,是排序后,再放进去的 这样是最好的)
registryProcessors.addAll(currentRegistryProcessors);
// 这个方法很简单,就是吧currentRegistryProcessors里面所有的处理器for循环一个个的执行掉
//所以这里会执行ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
// 此处把当前持有的执行对象给清空了,需要注意。以方便装载后续执行的处理器们
currentRegistryProcessors.clear();
//执行Ordered的BeanDefinitionRegistryPostProcessor,不包括我们在上面执行的。。。。。。。。
//执行剩下的BeanDefinitionRegistryPostProcessor。。。。。。。。
//执行BeanFactoryPostProcessor的方法postProcessBeanFactory
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
//忽略代码。。。。。
}
从上面代码可以看出,Spring是先执行ConfigurationClassPostProcessor
重写BeanDefinitionRegistry
的方法,在执行其重写BeanFactoryPostProcessor
的方法。
三、注册我们自己注入bean的BeanDefinition
其发生在ConfigurationClassPostProcessor
重写BeanDefinitionRegistry的postProcessBeanDefinitionRegistry
方法
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
//忽略代码..........
processConfigBeanDefinitions(registry);
}
//@Configuration类的注册并验证配置模型
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
//
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
//获取所有已经注册的BeanDefinition,注意,这时我们自己的bean的BeanDefinition还没有注册
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
//如果配置已经解析过了
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
logger.debug("");
}
}
//判断这些BeanDefinition所描述的类上是否有@Configuration,注解,如果有就把这个类设置成full模式
//判断这些BeanDefinition所描述的类上是否有@Bean,@Component,@ComponentScan,@Import,@ImportResource,注解,
//如果有就把这个类设置成lite模式,
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// 如果找不到@Configuration类,则立即返回
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);
});
// 检测通过封闭应用程序上下文提供的任何自定义bean名称生成策略
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
// 生成解析@Configuration的类ConfigurationClassParser
//他在初始化时会实例化ConditionEvaluator类,它是解析@Conditional注解
//他在初始化时会实例化ComponentScanAnnotationParser类,它是解析@ComponentScan注解
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 {
//解析配置类,把我们配置到bean封装成BeanDefinition,放到BeanDefinition池中
parser.parse(candidates);
//验证 如果是配置类,那么不能是final,因为他要进行继承代理
//@Bean标注的方法不能是private final的,
//注意方法可以是static的,虽然static方法不能被重写,但是他可以被继承
//尽量不要是static方法,因为CGLIB代理不能重写static方法。
parser.validate();
//获取通过配置类解析得到的类信息,包括配置类
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
//这段代码根据没有意义,因为alreadyParsed是空的,他还没有被赋值
configClasses.removeAll(alreadyParsed);
// 阅读模型并基于其内容创建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());
// 将ImportRegistry注册为bean以支持ImportAware@Configuration类
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
//清除外部提供的MetadataReaderFactory中的缓存;这是一个no操作
//对于共享缓存,因为它将被ApplicationContext清除。
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
1、执行ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法
2、获取当前spring中所有注册的BeanDefinition,注意这时候我们自己的bean的BeanDefinition还没有注册
3、判断这些BeanDefinition所描述的类上是否有@Configuration
,@Bean
,@Component
,@ComponentScan
,@Import
,@ImportResource
注解,如果有就把他放到configCandidates集合中。
注意:一般情况下,这时候容器存在我们自己定义的类只有配置类。因为我们使用了register方法把配置类事先注册到spring容器中去了。
代码如下
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(RootConfig.class);
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
//生产bean工厂
this();
//将配置类注入bean工厂
register(annotatedClasses);
refresh();
}
配置类可以理解是我们手动注册进去的。
4、生成ConfigurationClassParser解析类,调用其parse
方法解析这些配置类。
1、parser.parse(candidates);
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
//配置类在注册时都是以AnnotatedBeanDefinition类注册的,所以配置类进入这里
if (bd instanceof AnnotatedBeanDefinition) {
//其底层是processConfigurationClass方法
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);
}
}
//处理DeferredImportSelector类型的实现类
this.deferredImportSelectorHandler.process();
}
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
//根据{@code@Conditional}批注确定是否应跳过项。
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
//忽略代码。。。。。。。。
// 把ConfigurationClass类型转换成SourceClass类型
SourceClass sourceClass = asSourceClass(configClass);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
@Nullable
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
//处理@Component注解
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
//递归地首先处理任何成员(嵌套)类
processMemberClasses(configClass, sourceClass);
}
// 处理@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("");
}
}
// 处理@ComponentScan注解
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// 处理任何@Import注释
processImports(configClass, sourceClass, getImports(sourceClass), 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);
// 进程超类(如果有)
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();
}
}
// 没有超类->处理完成
return null;
}
为配置类进行Cglib代理
下面我们来看看ConfigurationClassPostProcessor
的postProcessBeanFactory
方法
通过用CGLIB增强的子类替换bean请求,准备在运行时为其提供服务的配置类
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//忽略代码。。。。。。
//生成配置类的代理类
enhanceConfigurationClasses(beanFactory);
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
//生成配置类的代理类
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
//循环所有的BeanDefinition
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);、
//判断其是否是全注解类,有@Configuration注解的就是全注解类
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
if (!(beanDef instanceof AbstractBeanDefinition)) {
throw new BeanDefinitionStoreException("");
}
else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
logger.info("");
}
//如果是全注解类就放到集合configBeanDefs中
configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
}
}
//没有找到配置类,直接返回
if (configBeanDefs.isEmpty()) {
return;
}
//代理类生成器
ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
//循环配置类
for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
//获取配置类
AbstractBeanDefinition beanDef = entry.getValue();
//如果@Configuration类被代理,则始终代理目标类
beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
try {
//获取当前配置类的class
Class<?> configClass = beanDef.resolveBeanClass(this.beanClassLoader);
if (configClass != null) {
//获取当前配置类class的代理class对象
Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
if (configClass != enhancedClass) {
if (logger.isTraceEnabled()) {
logger.trace("");
}
//重新设置配置类的BeanDefinition的中的class信息,赋值为代理类的class
beanDef.setBeanClass(enhancedClass);
}
}
}
catch (Throwable ex) {
throw new IllegalStateException("");
}
}
}
其中最重要的是这个方法
//利用代理器生成代理类
Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
其原理如下:
class ConfigurationClassEnhancer {
//对方法的增强策略
private static final Callback[] CALLBACKS = new Callback[] {
//拦截对任何{@link Bean}注释方法的调用,以确保正确处理Bean语义,如作用域和AOP代理
new BeanMethodInterceptor(),
//设置一个BeanFactory
new BeanFactoryAwareMethodInterceptor(),
NoOp.INSTANCE
};
public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
//如果配置类已经进行代理了(因为代理类都实现这个类)
if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
if (logger.isDebugEnabled()) {logger.debug(String.format(""));}
return configClass;
}
//如果不是代理类,生成代理类
Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
return enhancedClass;
}
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(configSuperClass);//代理类继承目标类
enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});//代理类实现EnhancedConfiguration接口
enhancer.setUseFactory(false);
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
//BeanFactoryAwareGeneratorStrategy作用是为代理类生成一个BeanFactory的public属性
enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
enhancer.setCallbackFilter(CALLBACK_FILTER);
enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
return enhancer;
}
假如我们的配置类名是RootCongfig,那么配置类的代理类就是这样
public CglibLRootCongfig extends RootCongfig implements EnhancedConfiguration{
public BeanFactory $$beanFactory
}
上面案例只能看出代理类与目标类的关系,还不能看出代理类对目标类方法的增强,代理类是使用BeanMethodInterceptor类对目标类进行增强,如下:
private static class BeanMethodInterceptor implements MethodInterceptor, ConditionalCallback {
//增强标注@Bean的方法以检查提供的BeanFactory
public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,MethodProxy cglibMethodProxy) throws Throwable {
//获取BeanFactory
ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
//获取当前@Bean标注方法生成bean的名字
String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);
// 确定此bean是否为作用域代理
if (BeanAnnotationHelper.isScopedProxy(beanMethod)) {
String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
if (beanFactory.isCurrentlyInCreation(scopedBeanName)) {
beanName = scopedBeanName;
}
}
//判断当前bean是否是factoryBean
if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&
factoryContainsBean(beanFactory, beanName)) {
Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
if (factoryBean instanceof ScopedProxyFactoryBean) {
// 作用域代理工厂bean是一种特殊情况,不应进一步代理
}
else {
// 它是一个候选工厂-继续改进
return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
}
}
//检查给定的方法beanMethod是否是容器当前调用的工厂方法,判断依据是方法名和方法参数类型,个数是否相同
if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
//如果是同一个方法就直接执行目标类的方法
return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
}
//否则直接调用方法其返回值
return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}
检查给定的方法beanMethod是否是容器当前调用的工厂方法,这个有的绕。
@ComponentScan(value = {"aop"})
@Configuration
public class RootConfig {
@Bean
public Demo demo(){
return new Demo();
}
@Bean
public Father father(){
demo()
return new Demo();
}
}
Spring会把当前执行当方法放到当前线程的ThreadLocal中
当执行demo方法时,当前线程执行方法是demo。配置类会执行demo的增强方法,因为调用方法和执行方法是同一个方法,且其方法内部没有RootConfig配置类当其他方法,所以直接执行代理类的父类,就是原配置类的方法。
当执行father方法时,当前线程执行方法是father。配置类会执行father的增强方法,因为其底层有RootConfig配置类当其他增强方法demo,所以就会执行demo的增强方法,这个调用方法是demo,执行方法是father,他们不是同一个方法,所以Spring会直接返回demo的值,不会进行demo方法的调用。