概述
在 spring 进行 执行refresh() 的invokeBeanFactoryPostProcessors(beanFactory),其中最重要的是执行ConfigurationClassPostProcessor 的postProcessBeanDefinitionRegistry()和 postProcessBeanFactory()这两个方法
在 postProcessBeanDefinitionRegistry()中,会进行类的扫描,然后生成对应的 beanDefinition,在这个过程会对配置类进行判断,如果加了@Configuration 机会将这个类元数据的属性标记为full ,反之标记为lite
至于这个变量真正的操作的方法并不在postProcessBeanDefinitionRegistry()中,而是在postProcessBeanFactory()里面
postProcessBeanFactory()
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
......
this.factoriesPostProcessed.add(factoryId);
if (!this.registriesPostProcessed.contains(factoryId)) {
// BeanDefinitionRegistryPostProcessor hook apparently not supported...
// Simply call processConfigurationClasses lazily at this point then.
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
// 判断是否需要对配置类生成代理对象
enhanceConfigurationClasses(beanFactory);
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
这里有一行很关键的代码enhanceConfigurationClasses(beanFactory) 判断这个BeanFactory中的配置类是否需要生成代理对象
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
MethodMetadata methodMetadata = null;
if (beanDef instanceof AnnotatedBeanDefinition) {
methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata();
}
if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
if (!abd.hasBeanClass()) {
...//省略try catch
abd.resolveBeanClass(this.beanClassLoader);
...
}
}
// 被@Configuration标注的配置类就是full
if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
....//省略
configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
}
}
if (configBeanDefs.isEmpty()) {
// nothing to enhance -> return immediately
return;
}
// 生成AppConfig的代理对象
ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
AbstractBeanDefinition beanDef = entry.getValue();
// If a @Configuration class gets proxied, always proxy the target class
beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
// Set enhanced subclass of the user-specified bean class
Class<?> configClass = beanDef.getBeanClass();
// 增强类
Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
if (configClass != enhancedClass) {
....
// 将增强类设置给beanDefinition,后续基于BeanDefinition产生的bean就是增加类的对象了
beanDef.setBeanClass(enhancedClass);
}
}
}
首先来看这段代码的第一个 for 循环:
beanFactory.getBeanDefinitionNames():从beanFactory中拿出所以的beanDefinition,然后循环遍历
其中一个非常重要的判断就是判断这个类的是不是标注了 full,如果标注了就说明是一个全配置类,然后将其加入到
configBeanDefs 这个集合中
第二个for循环:
就是对 configBeanDefs 这个集合进行处理,会对这里面的集合生成代理对象,然后将这个代理对象的类型设置到BeanDefinition的
beanClass属性里面
这就说明,之后spring 在对这个配置类里面标注了@Bean的方法getBean()的时候就会进入,这个代理对象的增强逻辑
下面直接来看 spring 对这个配置类道理进行了什么样的增强
intercept
public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
MethodProxy cglibMethodProxy) throws Throwable {
// 得到bean工厂和当前正在调用的beanMethod对应的beanName
ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);
if (BeanAnnotationHelper.isScopedProxy(beanMethod)) {
String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
if (beanFactory.isCurrentlyInCreation(scopedBeanName)) {
beanName = scopedBeanName;
}
}
// 省略部分代码
if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
...//省略日志
// invokeSuper 执行原本的逻辑
return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
}
return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}
为了方便讲解这里举个例子
@Configuration
public class AppConfig(
@Bean
public Mapper mapper(){
return new Mapper();
}
@Bean
public Server server(){
Mapper mapper = mapper();
return new Server(mapper);
}
)
这个例子就是Server 需要进行构造方法注入Mapper 对象,那么加了@Confguration 和没加 @Confguration会有什么区别呢?
加上@Confguration 获取的 Server 对象中的Mapper==Mapper对象
没加上@Confguration 获取的 Server 对象中的Mapper != Mapper对象
这里没加上 @Confguration 其实是比较好理解的,因为这个类的两个方法很显然是new 了两个 Mapper 对象
对于加上了@Confguration 我们结合代码进行分析
先是得到bean工厂和当前正在调用的beanMethod对应的beanName,
然后关键的判断的是 isCurrentlyInvokedFactoryMethod(beanMethod)
这个判断就是 如果现在真在实例化的是 Server ,但是在Server里面会执行 mapper(),那么这里会返回false
如果是实例化的是 Mpper ,那么这里返回的就是true
当返回true的时候就回去执行cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs),这里就是去invoke 父类的逻辑,也就是原本的mapper的逻辑
当返回false 的时候resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName),在这个方法里面有一行很关键的代码
Object beanInstance = (useArgs ? beanFactory.getBean(beanName, beanMethodArgs) :
beanFactory.getBean(beanName));
也就是说,当spring 实例化Server 对象的时候,会从spring 工厂里面去拿,那么即然是从spring的工厂里面去拿,如果这个Mapper是单例的,那么拿到的肯定就是同一个 Mapper 了