为何加上@Configuration注解的类会生成cglib代理?

@Configuration注解与@Component注解的区别?

首先我们来看下@Configuration这个注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {

   @AliasFor(annotation = Component.class)
   String value() default "";

   boolean proxyBeanMethods() default true;
}

可以看到其实@Configuration注解本质上也是一个@Component注解,那么这两者之间有什么不同呢?我们下面去测试一下:

@Configuration
@ComponentScan("com.zyh.learning.springsource")
public class AppConfig {

}
@Component
public class A {
    
}
AnnotationConfigApplicationContext acf = new AnnotationConfigApplicationContext(AppConfig.class);
A a = acf.getBean(A.class);
System.out.println(a);

此时A类加了一个@Component注解并且通过包扫描的方式加入到spring容器中,然后我们从spring容器就可以获取到A这个bean

可以看到A打印出来的是一个普通的Java对象的地址,而此时我们把A类上的@Component注解换成@Configuration注解

@Configuration
public class A {
    
}

 再从spring容器中获取A这个bean打印看看

神奇的是,打印出来的A的地址发生了变化,一眼看出来,发现A这个bean变成了一个由cglib创建的代理对象,所以,很明显,@Configuration注解和@Component注解都可以把对应的bean交给spring容器去管理,但是不一样的地方就在于,@Configuration注解所创建的bean是一个cglib代理对象,而@Component注解只是创建一个普通的Java对象

@Configuraton注解生成cglib代理的作用?

现在我们知道@Configuration注解和@Component注解都可以把bean放到spring容器进行管理,那么@Configuration注解把bean变成一个代理对象的作用是什么呢?我们现在看这样的一种场景:

@Component
public class AppConfig {

    @Bean
    public MyService myService() {
        MyService myService = new MyService();
        myService.setUserService(userService());
        return myService;
    }

    @Bean
    public UserService userService() {
        return new UserService();
    }
}
public class UserService {

    public UserService() {
        System.out.println("UserService...");
    }
}

我们在AppConfig配置类上加上@Component注解,然后通过@Bean注解的方式注入MyService和UserService这两个bean,并且在MyService的@Bean方法中还调用UserService的@Bean方法,现在我们来启动下spring容器看一下

可以看到UserService的@Bean方法调用了两次,创建了两个UserService实例,那我们把AppConfig配置类上的@Component注解换成@Configuration注解看下会不会不一样 

 可以看到把@Component注解换成了@Configuration注解之后,UserService的@Bean方法只调用了一次,也就是UserService实例只创建了一个,所以@Configuration注解就是为了避免用户显式地去调用@Bean方法,造成破坏了@Bean方法的bean的单例,而@Configuration注解能够做到这样避免用户显式调用@Bean方法的原理就是通过创建对应的配置类cglib代理对象去实现的,下面我们重点看一下@Configuraton注解底层是怎么通过cglib代理去实现@Bean方法不被用户显式调用

深入@Configuration注解生成cglib代理源码实现

 1.寻找加了@Configuration注解的BeanDefinition

org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanFactory

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
   int factoryId = System.identityHashCode(beanFactory);
   if (this.factoriesPostProcessed.contains(factoryId)) {
      throw new IllegalStateException(
            "postProcessBeanFactory already called on this post-processor against " + 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);
   }

   // 生成配置类cglib代理
   enhanceConfigurationClasses(beanFactory);
   beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}

ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor接口,而BeanDefinitionRegistryPostProcessor接口又是继承于BeanFactoryPostProcessor接口,众所周知BeanFactoryPostProcessor接口接口是一个BeanFactory的后置处理接口,也就是在BeanFactory初始化之后会调用该接口的postProcessBeanFactory方法,也就是上面的方法,其中里面会再调用enhanceConfigurationClasses方法,该方法就是生成cglib代理的关键方法

org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanFactory

/**
 * 从spring容器中找到所有候选的BeanDefinitions,候选状态由BeanDefinition的属性元数据确定(找到全配置的配置类,也就是加了@Configuration注解的配置类)
 * 然后通过{@link ConfigurationClassEnhancer}增强去对这些配置类进行cglib增强代理
 * @see ConfigurationClassEnhancer
 */
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
   Map configBeanDefs = new LinkedHashMap<>();
   // 遍历当前spring容器中所有的bd名称,这个for循环的目的就是找到所有全配置类(加了@Configuration注解的配置类)
   for (String beanName : beanFactory.getBeanDefinitionNames()) {
      // 根据bd名称获取到bd
      BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
      // 获取到CONFIGURATION_CLASS_ATTRIBUTE对应的属性值
      Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
      AnnotationMetadata annotationMetadata = null;
      MethodMetadata methodMetadata = null;
      if (beanDef instanceof AnnotatedBeanDefinition) {
         AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDef;
         annotationMetadata = annotatedBeanDefinition.getMetadata();
         methodMetadata = annotatedBeanDefinition.getFactoryMethodMetadata();
      }
      if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
         // Configuration class (full or lite) or a configuration-derived @Bean method
         // -> eagerly resolve bean class at this point, unless it's a 'lite' configuration
         // or component class without @Bean methods.
         AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
         if (!abd.hasBeanClass()) {
            boolean liteConfigurationCandidateWithoutBeanMethods =
                  (ConfigurationClassUtils.CONFIGURATION_CLASS_LITE.equals(configClassAttr) &&
                     annotationMetadata != null && !ConfigurationClassUtils.hasBeanMethods(annotationMetadata));
            if (!liteConfigurationCandidateWithoutBeanMethods) {
               try {
                  abd.resolveBeanClass(this.beanClassLoader);
               }
               catch (Throwable ex) {
                  throw new IllegalStateException(
                        "Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
               }
            }
         }
      }

      // 条件成立:说明这个bd对应的是一个配置类
      if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
         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;
   }

   // 如果这个类是一个全配置类,那么就使用cglib进行代理增强,目的是防止@Bean方法的手动重复调用造成单例的破坏
   ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
   for (Map.Entry 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();
      // 给这个全配置类创建一个cglib增强后的Class对象
      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()));
         }
         // 把cglib代理的Class对象设置到这个全配置类的bd中
         beanDef.setBeanClass(enhancedClass);
      }
   }
}

该方法的代码很多,但是做的事情很明确,就是去遍历spring容器中的所有BeanDefinition,找出扩展属性CONFIGURATION_CLASS_ATTRIBUTE对应的值等于CONFIGURATION_CLASS_FULL的BeanDefinition,那么这个属性从哪里来的呢?在执行postProcessBeanFactory方法之前,spring会去解析所有的配置类,包括包扫描,@Import的处理等等,简单来说就是会把能够给spring管理的bean对应的BeanDefinition都找出来放入到spring容器中,而这些BeanDefinition又分为两种,一种是全配置类,一种是半配置类,全配置类就是加了@Configuration注解并且proxyBeanMethods属性等于true,半配置类则是加了@Component,@ComponentScan,@Import,@ImportResource这几个注解的类(或者加了@Configuration注解但是proxyBeanMethods属性等于false),对于全配置类CONFIGURATION_CLASS_ATTRIBUTE对应的值就等于CONFIGURATION_CLASS_FULL,而对于半配置类CONFIGURATION_CLASS_ATTRIBUTE对应的值等于CONFIGURATION_CLASS_LITE。所以这里其实就是把加了@Configuration注解并且proxyBeanMethods属性等于true的BeanDefinition找出来。找出来之后需要干嘛呢?我们上面不是说了要创建对应的cglib代理吗,所以接下来需要去获取一个cglib增强之后的Class对象设置到这个BeanDefinition中了,而怎么去获取呢?这里就通过一个spring的一个cglib工具类ConfigurationClassEnhancer,该工具类封装了cglib的api,然后专门给全配置类去创建对应的cglib增强Class对象,具体增强的逻辑在ConfigurationClassEnhancer中已经定义好了,调用ConfigurationClassEnhancer的enhance方法,传入原始的Class对象就能够返回一个增强的cglib

2.创建cglib代理的Class对象 

org.springframework.context.annotation.ConfigurationClassEnhancer#enhance

public Class enhance(Class configClass, @Nullable ClassLoader classLoader) {
   if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
      if (logger.isDebugEnabled()) {
         logger.debug(String.format("Ignoring request to enhance %s as it has " +
               "already been enhanced. This usually indicates that more than one " +
               "ConfigurationClassPostProcessor has been registered (e.g. via " +
               "). This is harmless, but you may " +
               "want check your configuration and remove one CCPP if possible",
               configClass.getName()));
      }
      return configClass;
   }
   Class enhancedClass = createClass(newEnhancer(configClass, classLoader));
   if (logger.isTraceEnabled()) {
      logger.trace(String.format("Successfully enhanced %s; enhanced class name is: %s",
            configClass.getName(), enhancedClass.getName()));
   }
   return enhancedClass;
}

org.springframework.context.annotation.ConfigurationClassEnhancer#newEnhancer

/**
 * 创建一个新的CGLIB{@link Enhancer}实例
 */
private Enhancer newEnhancer(Class configSuperClass, @Nullable ClassLoader classLoader) {
   Enhancer enhancer = new Enhancer();
   enhancer.setSuperclass(configSuperClass);
   // 给配置类代理实现EnhancedConfiguration接口,该接口又继承了BeanFactoryAware接口,所以在配置类进行实例化的过程中能够回调到setBeanFactory方法
   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;
}

 可以看到在newEnhancer方法中都是调用cglib的api,比如设置superClass为需要增强的原始Class对象,设置代理要实现的接口,设置增强逻辑Callback等等

org.springframework.context.annotation.ConfigurationClassEnhancer#createClass

private Class createClass(Enhancer enhancer) {
   Class subclass = enhancer.createClass();
   // Registering callbacks statically (as opposed to thread-local)
   // is critical for usage in an OSGi environment (SPR-5932)...
   Enhancer.registerStaticCallbacks(subclass, CALLBACKS);
   return subclass;
}

然后最后调用enhancer的createClass方法,就可以得到一个增强后的Class对象,返回出去之后把这个增强的Class对象设置到BeanDefinition中就可以了

3.创建的cglib代理对象的增强逻辑 

(1)CallbackFilter

在创建enhancer对象时候,spring设置了一个CallbackFilter

private static class ConditionalCallbackFilter implements CallbackFilter {

   private final Callback[] callbacks;

   private final Class[] callbackTypes;

   public ConditionalCallbackFilter(Callback[] callbacks) {
      this.callbacks = callbacks;
      this.callbackTypes = new Class[callbacks.length];
      for (int i = 0; i < callbacks.length; i++) {
         this.callbackTypes[i] = callbacks[i].getClass();
      }
   }

   @Override
   public int accept(Method method) {
      for (int i = 0; i < this.callbacks.length; i++) {
         Callback callback = this.callbacks[i];
         if (!(callback instanceof ConditionalCallback) || ((ConditionalCallback) callback).isMatch(method)) {
            return i;
         }
      }
      throw new IllegalStateException("No callback available for method " + method.getName());
   }

   public Class[] getCallbackTypes() {
      return this.callbackTypes;
   }
}

 CallbackFilter的作用就是,当执行目标方法的时候会被accept方法拦截,在accpet方法会根据传入的目标方法去返回一个Callback增强,也就是通过这个CallbackFilter就可以实现调用不同的方法使用不同的增强Callback,而spring这里传的是ConditionalCallbackFilter,这个CallbackFilter在创建的时候需要传入一个Callback数组,这个Callback数组就是给accept方法去筛选具体的Callback返回的,我们下面看一下Callback数组中的Callback是哪几个

/**
 * 回调数组,根据CALLBACK_FILTER中accept方法返回的索引值去从该数组中选择对应的Callback
 */
private static final Callback[] CALLBACKS = new Callback[] {
      new BeanMethodInterceptor(),
      new BeanFactoryAwareMethodInterceptor(),
      NoOp.INSTANCE
};

spring传了三个Callback,分别是BeanMethodInterceptor,BeanFactoryAwareMethodInterceptor,NoOp.INSTANCE,最后一个NoOp.INSTANCE就是表示什么都不增强的意思,重点是BeanMethodInterceptor和BeanFactoryAwareMethodInterceptor

(2)给目标方法匹配Callback

在CallbackFilter的accpet方法中会通过每一个Callback的isMatch方法去对目标方法判断需要使用哪一个增强Callback进行增强,下面就看下BeanMethodInterceptor和BeanFactoryAwareMethodInterceptor这两个Callback的具体匹配条件

org.springframework.context.annotation.ConfigurationClassEnhancer.BeanMethodInterceptor#isMatch

public boolean isMatch(Method candidateMethod) {
   // 方法匹配条件:调用的方法不能是Object的方法,不是setBeanFactory方法,方法上需要有@Bean注解
   return (candidateMethod.getDeclaringClass() != Object.class &&
         !BeanFactoryAwareMethodInterceptor.isSetBeanFactory(candidateMethod) &&
         BeanAnnotationHelper.isBeanAnnotated(candidateMethod));
}

BeanMethodInterceptor的isMatch方法的匹配条件是:调用的方法不能是Object的方法,不是BeanFactoryAware接口的setBeanFactory方法,方法上需要有@Bean注解,简单的总结就是我们写的@Bean方法


org.springframework.context.annotation.ConfigurationClassEnhancer.BeanFactoryAwareMethodInterceptor#isMatch

public boolean isMatch(Method candidateMethod) {
   // 调用方法匹配条件:调用的方法是BeanFactoryAware接口的setBeanFactory方法
   return isSetBeanFactory(candidateMethod);
}
public static boolean isSetBeanFactory(Method candidateMethod) {
   return (candidateMethod.getName().equals("setBeanFactory") &&
         candidateMethod.getParameterCount() == 1 &&
         BeanFactory.class == candidateMethod.getParameterTypes()[0] &&
         BeanFactoryAware.class.isAssignableFrom(candidateMethod.getDeclaringClass()));
}

BeanFactoryAwareMethodInterceptor的isMatch方法的匹配条件则是:调用的方法是BeanFactoryAware接口的setBeanFactory方法。这里可能有人有个疑问,就是我们的配置类并没有实现BeanFactoryAware接口啊,从何而来的调用BeanFactoryAware接口的setBeanFactory方法呢?我们还是回到enhancer设置属性,看到有一个setInterfaces的属性设置,该属性就是设置代理对象需要实现的接口,而spring在这个属性中设置了EnhancedConfiguration这个接口

enhancer.setInterfaces(new Class[] {EnhancedConfiguration.class});

 但是可能有人会问,这也不是BeanFactoryAware接口呀,但是其实EnhancedConfiguration这个接口就是继承于BeanFactoryAware接口的

public interface EnhancedConfiguration extends BeanFactoryAware {
}

所以自然地cglib代理对象中自然就会有这个BeanFactoryAware接口的setBeanFactory方法了

(3)方法增强 

①BeanFactoryAwareMethodInterceptor

org.springframework.context.annotation.ConfigurationClassEnhancer.BeanFactoryAwareMethodInterceptor#intercept

public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
   // 获取到属性名称为$$beanFactory的属性
   Field field = ReflectionUtils.findField(obj.getClass(), BEAN_FACTORY_FIELD);
   Assert.state(field != null, "Unable to find generated BeanFactory field");
   // 给$$beanFactory这个属性赋值,值等于BeanFactory对象
   field.set(obj, args[0]);

   // 判断配置类是否已经实现了BeanFactoryAware接口,如果实现了,那么此时还需要调用该配置类自己实现的setBeanFactory方法
   if (BeanFactoryAware.class.isAssignableFrom(ClassUtils.getUserClass(obj.getClass().getSuperclass()))) {
      return proxy.invokeSuper(obj, args);
   }
   return null;
}

我们现在已经知道了BeanFactoryAwareMethodInterceptor这个Callback增强的目标方法是BeanFactoryAware接口的setBeanFactory方法,那么setBeanFactory这个方法什么时候会被调用呢?如果大家熟知bean的生命周期的话可以知道,如果一个bean实现了BeanFactoryAware接口的话,那么在实例化的过程中会回调BeanFactoryAware接口的setBeanFactory方法,而已回调的时候会把BeanFactory对象传给setBeanFactory方法。然后在spring回调setBeanFactory方法的时候,BeanFactoryAwareMethodInterceptor这个Callback就能够拦截到,执行intercept方法中的增强逻辑。在intercept方法中做的其实就是把回调过来的BeanFactory对象赋值给属性名称为$$beanFactory的属性,那么这里可能就有人会问了,$$beanFactory这个属性哪里来的?原来的配置类也没有这个属性呀,答案就是在cglib创建代理的时候,会生成$$beanFactory这个名称的属性,是在哪里设置生成$$beanFactory这个属性的呢?我们继续回看spring在设置enhancer属性的时候,有一个strategy的属性

enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));

setStrategy属性可以设置生成代理类的class文件字节码策略,这里具体设置的策略是BeanFactoryAwareGeneratorStrategy

private static class BeanFactoryAwareGeneratorStrategy extends
      ClassLoaderAwareGeneratorStrategy {

   public BeanFactoryAwareGeneratorStrategy(@Nullable ClassLoader classLoader) {
      super(classLoader);
   }

   @Override
   protected ClassGenerator transform(ClassGenerator cg) throws Exception {
      ClassEmitterTransformer transformer = new ClassEmitterTransformer() {
         @Override
         public void end_class() {
            declare_field(Constants.ACC_PUBLIC, BEAN_FACTORY_FIELD, Type.getType(BeanFactory.class), null);
            super.end_class();
         }
      };
      return new TransformingClassGenerator(cg, transformer);
   }

}
private static final String BEAN_FACTORY_FIELD = "$$beanFactory";

可以大概地看到在BeanFactoryAwareGeneratorStrategy中做的就是给生成的代理类添加一个属性,属性名为$$beanFactory,访问域是public,属性类型是BeanFactory。那么现在就可以总结下BeanFactoryAwareMethodInterceptor这个Callback的作用了,它的作用就是在spring回调BeanFactoryAware接口的seetBeanFactory方法的时候,把回调的BeanFactory对象赋值给$$beanFactory属性,而这个属性的由来就是cglib在创建代理类的时候添加进来的

②BeanMethodInterceptor 

org.springframework.context.annotation.ConfigurationClassEnhancer.BeanMethodInterceptor#intercept

public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
         MethodProxy cglibMethodProxy) throws Throwable {

   // 获取到$$beanFactory属性的值,也就是BeanFactory对象
   ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
   String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);

   // Determine whether this bean is a scoped-proxy
   if (BeanAnnotationHelper.isScopedProxy(beanMethod)) {
      String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
      if (beanFactory.isCurrentlyInCreation(scopedBeanName)) {
         beanName = scopedBeanName;
      }
   }
   
   if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&
         factoryContainsBean(beanFactory, beanName)) {
      Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
      if (factoryBean instanceof ScopedProxyFactoryBean) {
         // Scoped proxy factory beans are a special case and should not be further proxied
      }
      else {
         // It is a candidate FactoryBean - go ahead with enhancement
         return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
      }
   }

   // 条件成立:说明此时spring正在执行反射执行这个@Bean方法
   if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
      if (logger.isInfoEnabled() &&
            BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
         logger.info(String.format("@Bean method %s.%s is non-static and returns an object " +
                     "assignable to Spring's BeanFactoryPostProcessor interface. This will " +
                     "result in a failure to process annotations such as @Autowired, " +
                     "@Resource and @PostConstruct within the method's declaring " +
                     "@Configuration class. Add the 'static' modifier to this method to avoid " +
                     "these container lifecycle issues; see @Bean javadoc for complete details.",
               beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));
      }
      // 调用父类的原始@Bean方法返回bean实例,返回的bean实例会注册到spring容器中
      return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
   }

   // 代码来到这里说明此时的@Bean方法并不是由spring调用的,而是用户自身的代码显示调用的
   // 这种情况也就是在@Bean方法A中调用@Bean方法B,在调用@Bean方法B的时候上面的条件就不会成立,所以会执行到这里
   // 从BeanFactory中获取bean
   return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}

BeanMethodInterceptor的intercept方法比较长,关键的我们主要看最后的if判断

private boolean isCurrentlyInvokedFactoryMethod(Method method) {
   Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
   return (currentlyInvoked != null && method.getName().equals(currentlyInvoked.getName()) &&
         Arrays.equals(method.getParameterTypes(), currentlyInvoked.getParameterTypes()));
}

 在这个方法中主要就是SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod()这句代码会返回一个Method,那么这句代码的意思是什么呢?还有返回的Method又到底是什么?这里的话就要牵扯到bean实例化的时候了。我们先跳到spring在处理通过@Bean的方式实例bean的那块代码

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#instantiateUsingFactoryMethod

org.springframework.beans.factory.support.ConstructorResolver#instantiateUsingFactoryMethod

org.springframework.beans.factory.support.SimpleInstantiationStrategy#instantiate(org.springframework.beans.factory.support.RootBeanDefinition, java.lang.String, org.springframework.beans.factory.BeanFactory, java.lang.Object, java.lang.reflect.Method, java.lang.Object...)

public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
      @Nullable Object factoryBean, final Method factoryMethod, Object... args) {

   try {
      if (System.getSecurityManager() != null) {
         AccessController.doPrivileged((PrivilegedAction) () -> {
            ReflectionUtils.makeAccessible(factoryMethod);
            return null;
         });
      }
      else {
         ReflectionUtils.makeAccessible(factoryMethod);
      }

      Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
      try {
         // 把要执行的工厂方法放到currentlyInvokedFactoryMethod中
         currentlyInvokedFactoryMethod.set(factoryMethod);
         // 通过反射执行工厂实例的工厂方法
         Object result = factoryMethod.invoke(factoryBean, args);
         if (result == null) {
            result = new NullBean();
         }
         return result;
      }
      finally {
         if (priorInvokedFactoryMethod != null) {
            currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);
         }
         else {
            currentlyInvokedFactoryMethod.remove();
         }
      }
   }
   catch (IllegalArgumentException ex) {
      throw new BeanInstantiationException(factoryMethod,
            "Illegal arguments to factory method '" + factoryMethod.getName() + "'; " +
            "args: " + StringUtils.arrayToCommaDelimitedString(args), ex);
   }
   catch (IllegalAccessException ex) {
      throw new BeanInstantiationException(factoryMethod,
            "Cannot access factory method '" + factoryMethod.getName() + "'; is it public?", ex);
   }
   catch (InvocationTargetException ex) {
      String msg = "Factory method '" + factoryMethod.getName() + "' threw exception";
      if (bd.getFactoryBeanName() != null && owner instanceof ConfigurableBeanFactory &&
            ((ConfigurableBeanFactory) owner).isCurrentlyInCreation(bd.getFactoryBeanName())) {
         msg = "Circular reference involving containing bean '" + bd.getFactoryBeanName() + "' - consider " +
               "declaring the factory method as static for independence from its containing instance. " + msg;
      }
      throw new BeanInstantiationException(factoryMethod, msg, ex.getTargetException());
   }
} 
  

在spring实例化bean的时候会通过反射去调用这个bean所在的配置类的@Bean方法,而且在调用之前会把这个@Bean方法放到currentlyInvokedFactoryMethod中,那么放进去有什么作用呢?我们可以想一下,这一步是spring实例化bean的时候才触发的,如果我们是手动的调用这个@Bean方法,那么是根本不会调用到上面的方法的,currentlyInvokedFactoryMethod中也就不会有这个@Bean方法,然后此时回到isCurrentlyInvokedFactoryMethod方法的判断中

private boolean isCurrentlyInvokedFactoryMethod(Method method) {
   Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
   return (currentlyInvoked != null && method.getName().equals(currentlyInvoked.getName()) &&
         Arrays.equals(method.getParameterTypes(), currentlyInvoked.getParameterTypes()));
}

 判断的条件是currentlyInvoked不等于空,并且当前调用的目标方法要和currentlyInvoked方法名称,参数相同。如果该方法返回true,结合上面spring实例化bean的过程可以说明当前这个@Bean方法spring正在调用,而如果返回false的话,那么就表示当前这个@Bean方法并不是由spring实例化去调用的,而是我们用户手动去调用的,此时的话就会执行resolveBeanReference方法,resolveBeanReference方法就会从spring容器中去拿这个@Bean方法方法所对应的bean并返回,resolveBeanReference方法代码如下:

private Object resolveBeanReference(Method beanMethod, Object[] beanMethodArgs,
      ConfigurableBeanFactory beanFactory, String beanName) {

   boolean alreadyInCreation = beanFactory.isCurrentlyInCreation(beanName);
   try {
      if (alreadyInCreation) {
         beanFactory.setCurrentlyInCreation(beanName, false);
      }
      boolean useArgs = !ObjectUtils.isEmpty(beanMethodArgs);
      if (useArgs && beanFactory.isSingleton(beanName)) {
         for (Object arg : beanMethodArgs) {
            if (arg == null) {
               useArgs = false;
               break;
            }
         }
      }

      // 从spring容器中获取这个bean
      Object beanInstance = (useArgs ? beanFactory.getBean(beanName, beanMethodArgs) :
            beanFactory.getBean(beanName));
      if (!ClassUtils.isAssignableValue(beanMethod.getReturnType(), beanInstance)) {
         // Detect package-protected NullBean instance through equals(null) check
         if (beanInstance.equals(null)) {
            if (logger.isDebugEnabled()) {
               logger.debug(String.format("@Bean method %s.%s called as bean reference " +
                     "for type [%s] returned null bean; resolving to null value.",
                     beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),
                     beanMethod.getReturnType().getName()));
            }
            beanInstance = null;
         }
         else {
            String msg = String.format("@Bean method %s.%s called as bean reference " +
                  "for type [%s] but overridden by non-compatible bean instance of type [%s].",
                  beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),
                  beanMethod.getReturnType().getName(), beanInstance.getClass().getName());
            try {
               BeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition(beanName);
               msg += " Overriding bean of same name declared in: " + beanDefinition.getResourceDescription();
            }
            catch (NoSuchBeanDefinitionException ex) {
               // Ignore - simply no detailed message then.
            }
            throw new IllegalStateException(msg);
         }
      }
      Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
      if (currentlyInvoked != null) {
         String outerBeanName = BeanAnnotationHelper.determineBeanNameFor(currentlyInvoked);
         // 注册两个bean之间的依赖关系
         beanFactory.registerDependentBean(beanName, outerBeanName);
      }
      return beanInstance;
   }
   finally {
      if (alreadyInCreation) {
         beanFactory.setCurrentlyInCreation(beanName, true);
      }
   }
}

关键就是调用了getBean方法从spring容器中获取这个@Bean方法对应的bean

总结

@Configuration注解能够使得加了它的对应的配置类在spring容器中是一个cglib代理bean,让配置类实例变成cglib代理实例的作用就是防止@Bean方法A又调用@Bean方法B的这种场景破坏了bean的单例性。解决这种场景的原理就是在spring实例化@Bean方法A对应的bean的时候,会通过反射调用配置类的@Bean方法A,在反射调用之前@Bean方法A放到currentlyInvokedFactoryMethod中,然后由于配置类已经是一个cglib代理对象了,所以会被BeanMethodInterceptor这个Callback进行拦截增强,此时判断到currentlyInvokedFactoryMethod中存在方法A,那么就直接执行这个@Bean方法A了,而@Bean方法A中又调用了@Bean方法B,所以此时在执行@Bean方法A的时候,@Bean方法B也会被BeanMethodInterceptor这个Callback所拦截增强,但是,此时currentlyInvokedFactoryMethod中的方法是@Bean方法A,所以isCurrentlyInvokedFactoryMethod方法判断返回的是false,也就是走resolveBeanReference方法从spring容器中去获取@Bean方法B对应的bean

你可能感兴趣的:(Spring,java,spring)