ConfigurationClassPostProcessor
继承了 BeanDefinitionRegistryPostProcessor
接口,它实现了 postProcessBeanDefinitionRegistry
和其父类的 BeanFactoryPostProcessor#postProcessBeanFactory
方法。
关于 postProcessBeanDefinitionRegistry
方法的解析可以参看: Spring5 源码学习 (5) ConfigurationClassPostProcessor (上) 。
现在我们来看一下 ConfigurationClassPostProcessor#postProcessBeanFactory
方法的源码。
ConfigurationClassPostProcessor#postProcessBeanFactory
方法也在 refresh();
方法中执行 invokeBeanFactoryPostProcessors(beanFactory);
方法时被调用的。
//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); // 在 this.postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) 方法中 // 调用this.registriesPostProcessed.add(registryId); // if条件不成立 if (!this.registriesPostProcessed.contains(factoryId)) { // BeanDefinitionRegistryPostProcessor hook apparently not supported... // Simply call processConfigurationClasses lazily at this point then. processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory); } // 对配置类进行增强 enhanceConfigurationClasses(beanFactory); // 创建 ImportAwareBeanPostProcessor ,来支持 ImportAware ,调用ImportAware.setImportMetadata方法 beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory)); }
主要做了两件事:
ImportAwareBeanPostProcessor
来支持 ImportAware
接口。 主要来看一下对配置类进行增强方法 enhanceConfigurationClasses(beanFactory);
的源码。
Spring会对Full Configuration 进行代理,拦截 @Bean
方法,以确保正确处理 @Bean
语义。这个增强的代理类就是在 enhanceConfigurationClasses(beanFactory)
方法中产生的,源码如下:
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) { Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>(); //获取所有的BeanDefinitionName,之前已经完成了bean的扫描,这里会获取到所有的beanName for (String beanName : beanFactory.getBeanDefinitionNames()) { BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName); // 校验是否为FullConfigurationClass,也就是是否被标记了 @Configuration 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'."); } //如果是FullConfigurationClass,则放到变量configBeanDefs中 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) { // 对 FullConfigurationClass 进行增强 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())); } //将BeanClass设置为增强后的类 beanDef.setBeanClass(enhancedClass); } } } catch (Throwable ex) { throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), ex); } } }
获取所有为FullConfigurationClass的 BeanDefinition
(即标注 @Configuration
的配置类),然后依次调用 enhancer.enhance(configClass, this.beanClassLoader);
方法,对配置类进行增强,将方法返回 Class<?> enhancedClass
的设置到 BeanDefinition
中( eanDef.setBeanClass(enhancedClass);
),之后Spring创建该 BeanDefinition
时就会使用这个增强类来创建。
下面是 enhancer.enhance(configClass, this.beanClassLoader);
方法源码:
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 " + "<context:annotation-config>). 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; }
具体来看一下 newEnhancer(configClass, classLoader
方法,这个方法负责创建Full Configuration增强类。
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) { // Spring重新打包了CGLIB(使用Spring专用补丁;仅供内部使用) // 这样可避免在应用程序级别或第三方库和框架上与CGLIB的依赖性发生任何潜在冲突 // https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/cglib/package-summary.html Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(configSuperClass); // 设置需要实现的接口,也就是说,我们的配置类的cglib代理还实现的 EnhancedConfiguration 接口 enhancer.setInterfaces(new Class<?>[]{EnhancedConfiguration.class}); enhancer.setUseFactory(false); // 设置命名策略 enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); // 设置生成器创建字节码策略 // BeanFactoryAwareGeneratorStrategy 是 CGLIB的DefaultGeneratorStrategy的自定义扩展,主要为了引入BeanFactory字段 enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader)); // 设置增强 enhancer.setCallbackFilter(CALLBACK_FILTER); enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes()); return enhancer; }
这里的 Enhancer
对象是 org.springframework.cglib.proxy.Enhancer
,那它和 cglib
是什么关系呢?
Spring's repackaging of CGLIB 3.2 (with Spring-specific patches; for internal use only).This repackaging technique avoids any potential conflicts with dependencies on CGLIB at the application level or from third-party libraries and frameworks.
引用自: https://docs.spring.io/spring...
大致就是说,Spring重新打包了CGLIB(使用Spring专用补丁,仅供内部使用) ,这样可避免在应用程序级别或第三方库和框架上与CGLIB的依赖性发生任何潜在冲突。
那具体做了哪些增强呢?
EnhancedConfiguration
接口。这是一个空的标志接口,仅由Spring框架内部使用,并且由所有 @Configuration
CGLIB子类实现,该接口继承了 BeanFactoryAware
接口。 BeanFactoryAwareGeneratorStrategy
继承了cglib的 DefaultGeneratorStrategy
,其主要作用是为了让子类引入 BeanFactory
字段和设置 ClassLoader
。 Callback
: private static final Callback[] CALLBACKS = new Callback[]{ // 拦截 @Bean 方法的调用,以确保正确处理@Bean语义 new BeanMethodInterceptor(), // 拦截 BeanFactoryAware#setBeanFactory 的调用 new BeanFactoryAwareMethodInterceptor(), NoOp.INSTANCE };
BeanMethodInterceptor
:负责拦截 @Bean
方法的调用,以确保正确处理 @Bean
语义。 BeanFactoryAwareMethodInterceptor
:负责拦截 BeanFactoryAware#setBeanFactory
方法的调用,因为增强的配置类实现了 EnhancedConfiguration
接口(也就是实现了 BeanFactoryAwar
接口)。 下面,我们就以 AppConfig
为例,来学习增强Callback相关源码。
@Configuration @ComponentScan public class AppConfig { @Bean public String name() throws Exception { getUserBean().getObject(); return "程序员小黑"; } @Bean public FactoryBean getUserBean() { return new FactoryBean<UserBean>() { @Override public UserBean getObject() throws Exception { System.out.println("1111"); return new UserBean("shen", 17); } @Override public Class<?> getObjectType() { return UserBean.class; } }; } }
主要作用是:拦截 @Bean
方法的调用,以确保正确处理 @Bean
语义。当调用 @Bean
方法时,就会被以下代码所拦截:
//BeanMethodInterceptor#intercept源码 public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs, MethodProxy cglibMethodProxy) throws Throwable { // enhancedConfigInstance 已经是配置类的增强对象了,在增强对象中,有beanFactory字段的 // 获取增强对象中的beanFactory ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance); // 获取beanName 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; } } // To handle the case of an inter-bean method reference, we must explicitly check the // container for already cached instances. // First, check to see if the requested bean is a FactoryBean. If so, create a subclass // proxy that intercepts calls to getObject() and returns any cached bean instance. // This ensures that the semantics of calling a FactoryBean from within @Bean methods // is the same as that of referring to a FactoryBean within XML. See SPR-6602. // 检查容器中是否存在对应的 FactoryBean 如果存在,则创建一个增强类 // 通过创建增强类来代理拦截 getObject()的调用 , 以确保了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) { // Scoped proxy factory beans are a special case and should not be further proxied } else { // It is a candidate FactoryBean - go ahead with enhancement // 创建增强类,来代理 getObject()的调用 // 有两种可选代理方式,cglib 和 jdk // Proxy.newProxyInstance( // factoryBean.getClass().getClassLoader(), new Class<?>[]{interfaceType}, // (proxy, method, args) -> { // if (method.getName().equals("getObject") && args == null) { // return beanFactory.getBean(beanName); // } // return ReflectionUtils.invokeMethod(method, factoryBean, args); // }); return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName); } } // 判断当时执行的方法是否为@Bean方法本身 // 举个例子 : 如果是直接调用@Bean方法,也就是Spring来调用我们的@Bean方法,则返回true // 如果是在别的方法内部,我们自己的程序调用 @Bean方法,则返回false if (isCurrentlyInvokedFactoryMethod(beanMethod)) { // The factory is calling the bean method in order to instantiate and register the bean // (i.e. via a getBean() call) -> invoke the super implementation of the method to actually // create the bean instance. 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())); } // 如果返回true,也就是Spring在调用这个方法,那么就去真正执行该方法 return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs); } //否则,则尝试从容器中获取该 Bean 对象 // 怎么获取呢? 通过调用 beanFactory.getBean 方法 // 而这个getBean 方法,如果对象已经创建则直接返回,如果还没有创建,则创建,然后放入容器中,然后返回 return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName); }
enhancedConfigInstance
是配置类的增强对象。从增强对象中获取 beanFactory
和 beanName
。举个例子:当Spring调用 name()
方法时, beanName
就是 name
。 FactoryBean
,如果存在,则创建一个增强类,来代理 getObject()
的调用。在本示例中,如果读者将 name()
方法注释删掉之后程序并不会执行到这一步。因为Spring调用 getUserBean()
方法时,容器中并没有存在对应的 FactoryBean
。因为只有第二次调用 getUserBean()
方法容器中才会存在对应的 FactoryBean
。 @Bean
方法本身,如果是,则直接调用该方法,不做增强拦截;否则,则尝试从容器中获取该 Bean
对象。 BeanFactoryAwareMethodInterceptor
方法就比较简单,其作用为拦截 BeanFactoryAware#setBeanFactory
的调用,用于获取 BeanFactory
对象。
// BeanFactoryAwareMethodInterceptor#intercept 源码 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { Field field = ReflectionUtils.findField(obj.getClass(), BEAN_FACTORY_FIELD); Assert.state(field != null, "Unable to find generated BeanFactory field"); field.set(obj, args[0]); // Does the actual (non-CGLIB) superclass implement BeanFactoryAware? // If so, call its setBeanFactory() method. If not, just exit. if (BeanFactoryAware.class.isAssignableFrom(ClassUtils.getUserClass(obj.getClass().getSuperclass()))) { return proxy.invokeSuper(obj, args); } return null; }
最后,再补充说明一点,我们可以通过如下配置来获取Spring为我们生成的CGLIB代理增强类的class文件:
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "spring-study/docs/classes");
源码注释GITHUB地址: https://github.com/shenjianen...
欢迎关注公众号,一起学习成长。