ConfigurationClassPostProcessor
继承了 BeanDefinitionRegistryPostProcessor
接口,它实现了 postProcessBeanDefinitionRegistry
和其父类的 BeanFactoryPostProcessor#postProcessBeanFactory
方法。
关于 postProcessBeanDefinitionRegistry
方法的解析可以参看:Spring5 源码学习 (5) ConfigurationClassPostProcessor (上)。
现在我们来看一下 ConfigurationClassPostProcessor#postProcessBeanFactory
方法的源码。
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);
的源码。
enhanceConfigurationClasses(beanFactory)增强 Full Configuration
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;
}
创建 Full Configuration 增强类
具体来看一下 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
接口)。
设置增强 Callback
下面,我们就以 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;}
};
}
}
BeanMethodInterceptor
主要作用是:拦截 @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
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;
}
输出增强类 class 文件
最后,再补充说明一点,我们可以通过如下配置来获取 Spring 为我们生成的 CGLIB 代理增强类的 class 文件:
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "spring-study/docs/classes");
源码注释 GITHUB 地址:https://github.com/shenjianen…
欢迎关注公众号,一起学习成长。