Spring核心源码(三)@Configuration注解设计思想

​invokeBeanFactoryPostProcessors(下)

在上一小节我们分析完了invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);这个方法干了那些事情,现在我们继续对后文做分析,如图:

image

上图Spring进行循环,判断是否有遗漏掉的后置处理器没有解析,一般情况下,currentRegistryProcessors会是0,我们运行代码都会直接跳过,继续往下走:

image

这里是Spring最后一次对BeanDefinitionRegistryPostProcessor后置处理器进行解析,主要是针对一些父类层级关系,通常也为0,所以依旧不会有什么作用。好了,接下来到了关键代码了

image

我们对invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);进行跟踪->postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) ,我们将代码停在下图:

image

注意AppConfig.class的变化

image

这里它还是一个普通的类,我们调试下一步

image

可以发现,Spring将其增强成为了cglib增强类,那么AppConfig为什么会增强呢?我们下面进行详细分析

@Configuration

当我们将 @Configuration取消时,

image

我们调试停在上面的代码

image

可以看到这里的配置类并没有被增强,所以可以得出结论,我们的@Configuration可以将我们的普通类进行增强,不知读者是否还记得我们在上一章所讲full吗,如果是 @Configuration类,Spring会认为这是一个配置类就会将其标识full,而这个full就是代表配置类是否需要增强,后面我们会在源码中进行证明,好了,说了这么多,相信读者应该对 @Configuration
有一定的了解,现在我们来探讨为什么Spring要增强 配置类,这里我们对加上@Configuration和取消@Configuration进行测试,我们看下面代码:

image

第一种情况-》取消@Configuration

image

第二种情况-》加上@Configuration

image

我们可以看到有了@Configuration,我们的user1()和user2()方法返回的对象是同一个对象,当然这里还有第三种情况加上static,读者可以自行测试看看又是什么情况,结果会发现代理功能会失效,至于为什么会失效我们在后面的源码会详细说明。好了我们大概知道了@Configuration的作用,那么Spring是如何对@Configuration进行增强的呢,我们回到源码中:

image

进入enhanceConfigurationClasses

public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
    Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
​
    //找到config注解类,这里就可以看到full和lite了,如果full会变成增强类,目的是为了实现单例
    for (String beanName : beanFactory.getBeanDefinitionNames()) {
      BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
      if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
        if (!(beanDef instanceof AbstractBeanDefinition)) {
          throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
              beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
        }
        else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
          logger.info("Cannot enhance @Configuration bean definition '" + beanName +
              "' since its singleton instance has been created too early. The typical cause " +
              "is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
              "return type: Consider declaring such methods as 'static'.");
        }
        configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
      }
    }
    if (configBeanDefs.isEmpty()) {
      // nothing to enhance -> return immediately
      return;
    }
​
    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);
      try {
        // Set enhanced subclass of the user-specified bean class
        Class<?> configClass = beanDef.resolveBeanClass(this.beanClassLoader);
        if (configClass != null) {
          Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
          if (configClass != enhancedClass) {
            if (logger.isTraceEnabled()) {
              logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
                  "enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
            }
            beanDef.setBeanClass(enhancedClass);
          }
        }
      }
      catch (Throwable ex) {
        throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
      }
    }
  }

这里(ConfigurationClassUtils.isFullConfigurationClass(beanDef))会判断有没有标识了FULL的配置类,如果没有下面configBeanDefs
会为空直接返回,如果不为空,对配置类增强,我们锁定这段代码Class<?> enhancedClass = enhancer.enhance(configClass,
this.beanClassLoader);-》Class<?> enhancedClass createClass(newEnhancer(configClass,classLoader));-》
newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader)最后来到了这里:

image

在对@Configuration做详细分析时,笔者可以先自行思考,Spring对配置类进行增强之后如何做到采用不同的方式去创建对象,为什么在Spring的容器里都只会存放一份Bean,如果要实现这种功能,是不是需要改变创建对象的方式呢?那么既然我们的工厂我们的@Bean.class是创建对象交给Spring管理,那么如果我们创建对象的方式先通过工厂里面获取,如果获取不到我们再创建对象交给Spring管理是不是就能够实现呢?好了,我想读者应该有些思路了,我们再看一张图

image

图上大致讲解了配置类转变为增强类后大概是什么样子的,从图上我们可以看到增强代理类有个私有变量,这个变量存放着我们的工厂,那么为什么需要这个工厂我想读者应该有所顿悟。好了我们再回到源码:

image

这里Spring是采用CGLIB增强,如果读者没有了解过CGLIB的话,最好在网上了解下CGLIB的使用,这里不再赘述。首先将目标类交给enhancer,其次添加了一个接口,EnhanceConfiguration.class,这个类是CGLIB实现增强的核心,我们点进这个接口会发现它实现了BeanFactoryAwae接口,然后我们继续往下走,看到setStrategy(newBeanFactoryAwareGeneratorStrategy(classLoader)),我们点进去

image

image

如图我们可以大概才到,Spring在这里添加了一个策略,这个策略是声明一个变量名为"$$beanFactory"的公共属性,再回想我们之前添加的接口是不是可以得到工厂,那么我么你现在还差一步,如何将前面的原料加工就是我们代理需要去做的事情:

image

这个Callback笔者就不分析了,因为涉及到CGLIB的知识,如果读者有情趣可以自行研究。好了我们生成代理后还差一件事情,那就是如何将我们拿到的工厂赋值给代理类得变量中,看下面代码

image

我们点进去

image

这里读者是不是豁然开朗,是不是觉得Spring的设计如神一般的存在啊,好了当我们了解到这里其实
invokeBeanFactoryPostProcessors这个方法也差不多结束了,当然还有一些更细节的地方笔者会作为单独的章节进行描述,哎,总算是到了一半了,什么才一半?,毕竟我们真正的对象实例还没开始呢,好的我们在下一小节会对Spring剩余部分进行深度分

文章来源微信公众号《七天0》

下一章节,Spring对象实例化和初始化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值