【源码】Spring —— @Configuration 3 FULL 配置类的原理
本文已参与「新人创作礼」活动,一起开启掘金创作之路。
前言
之前的章节解读了 配置类 的解析时机与过程,同时提到了 FULL 和 LITE 两种模式的 配置类,他们的区别在于,前者会代为管理 @Bean 之间的依赖关系,换句话说:对于 bean 方法的调用会转而去 BeanFactory 中获取对应的 bean 实例,看个代码示例:
@Configuration
public class ProxyConfigurationConfig {
class Son {
public Son() {
System.out.println("son");
}
}
class Parent {
Son son;
public Parent(Son son) {
this.son = son;
System.out.println("parent");
}
public Son getSon() {
return son;
}
public void setSon(Son son) {
this.son = son;
}
}
@Bean
public Son son() {
return new Son();
}
@Bean
public Parent parent() {
return new Parent(son());
}
}
可以看到,尽管 parent 方法调用了 son 方法,但 Son 实例确实只初始化了一次,也就是说,son 方法获取实例不再是抽象创建,而是从 BeanFactory 获取
当然,这不是猜测,下文给出相关源码解读
版本
springframework:5.2.x
ConfigurationClassPostProcessor#postProcessBeanFactory
之前的章节已解读,在 容器 的启动生命周期中,会依次调用 ConfigurationClassPostProcessor 的 processConfigBeanDefinitions 和 postProcessBeanFactory 方法,前者正是我们前面的章节重点解读的 配置类 的解析,后者就是本章节的重点,配置类 的代理
PS:这种动态改变行为的实现,基本就是 代理 没跑了
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)) {
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
// 代理处理
enhanceConfigurationClasses(beanFactory);
// 给容器注册一个 ImportAwareBeanPostProcessor
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
代理的实现就是 enhanceConfigurationClasses 方法
ConfigurationClassPostProcessor#enhanceConfigurationClasses
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
// ... 筛选出所有的 FULL 配置类
// 遍历进行 CGLIB 代理,由 ConfigurationClassEnhancer#enhance 方法实现
ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
AbstractBeanDefinition beanDef = entry.getValue();
beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
Class<?> configClass = beanDef.getBeanClass();
Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
if (configClass != enhancedClass) {
/**
* 这里替换了 bd 的 beanClass 属性,因此
* 因此之后创建的 bean 就是一个增强过的代理对象
* 同时,这个代理对象可以参与后续 bean 的生命周期,比如:属性赋值
*/
beanDef.setBeanClass(enhancedClass);
}
}
}
- 筛选出所有的 FULL 配置类
- 遍历进行代理,此处使用 CGLIB 代理,因为之前提到 配置类 会同样解析父类的
@Bean方法,也就是说,配置类允许 继承 行为 - 代理逻辑由
ConfigurationClassEnhancer#enhance方法实现
ConfigurationClassEnhancer#enhance
public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
// ...
// 创建代理
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 --------------------
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(configSuperClass);
// 设置的接口 EnhancedConfiguration 继承了 BeanFactoryAware
// 因此代理类可以持有 BeanFactory 对象
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;
}
-------------------- createClass --------------------
private Class<?> createClass(Enhancer enhancer) {
Class<?> subclass = enhancer.createClass();
// 拦截器
Enhancer.registerStaticCallbacks(subclass, CALLBACKS);
return subclass;
}
------------------------------------------------
// 注册的三(两)个拦截器
private static final Callback[] CALLBACKS = new Callback[] {
new BeanMethodInterceptor(),
new BeanFactoryAwareMethodInterceptor(),
NoOp.INSTANCE
};
Enhancer 创建代理对象,注册了两个核心拦截器 BeanMethodInterceptor BeanFactoryAwareMethodInterceptor,都是 ConfigurationClassEnhancer 的内部类(高内聚的体现)
BeanFactoryAwareMethodInterceptor
private static class BeanFactoryAwareMethodInterceptor implements MethodInterceptor, ConditionalCallback {
@Override
@Nullable
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 将 BeanFactory 设置到 $$beanFactory 字段
Field field = ReflectionUtils.findField(obj.getClass(), BEAN_FACTORY_FIELD);
Assert.state(field != null, "Unable to find generated BeanFactory field");
field.set(obj, args[0]);
if (BeanFactoryAware.class.isAssignableFrom(ClassUtils.getUserClass(obj.getClass().getSuperclass()))) {
return proxy.invokeSuper(obj, args);
}
return null;
}
@Override
public boolean isMatch(Method candidateMethod) {
return isSetBeanFactory(candidateMethod);
}
// 拦截 setBeanFactory 方法
public static boolean isSetBeanFactory(Method candidateMethod) {
return (candidateMethod.getName().equals("setBeanFactory") &&
candidateMethod.getParameterCount() == 1 &&
BeanFactory.class == candidateMethod.getParameterTypes()[0] &&
BeanFactoryAware.class.isAssignableFrom(candidateMethod.getDeclaringClass()));
}
}
- 因为间接实现了 BeanFactoryAware 接口,因此
setBeanFactory持有 BeanFactory 对象,此处把该对象设置到$$beanFactory字段中 setBeanFactory方法原逻辑保持
BeanMethodInterceptor
核心的拦截器,逻辑也比较复杂,主要作用就是通过拦截 @Bean 方法,将方法指向 容器 中获取对应的 bean 实例
BeanMethodInterceptor#isMatch
// 拦截 @Bean 方法
public boolean isMatch(Method candidateMethod) {
return (candidateMethod.getDeclaringClass() != Object.class &&
!BeanFactoryAwareMethodInterceptor.isSetBeanFactory(candidateMethod) &&
BeanAnnotationHelper.isBeanAnnotated(candidateMethod));
}
主要是拦截 @Bean 注解标注的方法
BeanMethodInterceptor#intercept
public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
MethodProxy cglibMethodProxy) throws Throwable {
// 从之前设置的 $$beanFactory 字段获取 beanFactory
ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
// 解析 beanName,一般就是方法名
String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);
// Scope 相关
if (BeanAnnotationHelper.isScopedProxy(beanMethod)) {
String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
if (beanFactory.isCurrentlyInCreation(scopedBeanName)) {
beanName = scopedBeanName;
}
}
/**
* 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) {
else {
return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
}
}
/**
* 检查给定的方法是否与容器当前调用的工厂方法相对应
* @Bean
* public Son son() {
* return new Son();
* }
*
* @Bean
* public Parent parent() {
* return new Parent(son());
* }
* 具体的说,形如以上的示例:
* 在创建 Son 的 bean 实例时调用 son() 方法,即表明
* 给定的方法与容器当前调用的工厂方法相对应,则
* 不作处理,对应于方法 cglibMethodProxy.invokeSuper
* 在创建 Parent 的 bean 实例时调用到 son() 方法,
* 则给定的方法不与容器当前调用的工厂方法相对应,
* 需要代理指向 beanFactory#getBean 方法,
* 对应于 resolveBeanReference 方法
*/
if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
/**
* 这个地方的场景是这样的:
* BeanFactoryPostProcessor 的 bean 实例的创建理论上是要先于 配置类 bean 的
* 但是如果在配置类中创建 BeanFactoryPostProcessor 类型的 bean
* 则在创建该 bean 之前会先去创建对应 配置类 的 bean,导致 @Autowired 等注解无法处理
* 因此此处会给出日志信息,同时给出解决方法:将 BeanFactoryPostProcessor 的 bean
* 声明为 static 类型
*/
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()));
}
return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
}
return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}
该方法便是代理处理的核心逻辑了,注释中给出了详细的解读,这里做个简单地总结:
- 取出我们上一个 拦截器 设置的
beanFactory用于支持后续操作 - 对于 FactoryBean,我们将其
getObject方法代理到beanFactory#getBean - 对于
@Bean方法的调用:
1)如果给定的方法与容器当前调用的工厂方法相对应,则不作处理,比如:创建Son的实例时调用son()方法是不用处理的,而创建Parent的实例时调用son()方法是要被处理成从容器获取的
2)反之,将其代理到beanFactory#getBean
总结
至此,对 FULL 配置里的代理做了基本的解读,再往后的细节便不再解读了,如果想了解,文末会给出对应的链接以供参考
借助这波操作,配置类 内对其他 @Bean 方法的调用便指向了从 容器 中获取,在这很多业务场景下是必须的