Spring 版本: 5.2.2.RELEASE
本文涉及到 cglib 的知识,可以在 Java:使用 cglib 实现动态代理 了解。
@Bean
必须在 @Configuration
注解的类中才能生效。
所以 @Bean
有3个阶段:
- 增强
@Configuration
注解的类 - Spring 扫描得到所有 @Bean 方法
- 生成 Spring bean 实例
原理
阶段1:增强 @Configuration
注解的类
大致执行时序:
AbstractApplicationContext -> AbstractApplicationContext: refresh()
AbstractApplicationContext -> AbstractApplicationContext: invokeBeanFactoryPostProcessors()
AbstractApplicationContext -> PostProcessorRegistrationDelegate: invokeBeanFactoryPostProcessors
PostProcessorRegistrationDelegate -> ConfigurationClassPostProcessor: enhanceConfigurationClasses
ConfigurationClassPostProcessor -> ConfigurationClassEnhancer: enhance
ConfigurationClassEnhancer # enhance 执行完后,我们会得到 @Configuration 注解的类的一个增强类。这个增强类是基于 cglib 实现的原始类的子类。
ConfigurationClassEnhancer 中的重点代码:
// 这个callback,会在生成 spring bean 时被调用
private static final Callback[] CALLBACKS = new Callback[] {
new BeanMethodInterceptor(),
new BeanFactoryAwareMethodInterceptor(),
NoOp.INSTANCE
};
// 对类进行增强(即用cglib对类代理一层)
public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
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;
}
// 下面是 cglib 的增强代码
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(configSuperClass);
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;
}
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;
}
因为增强类是动态生成的,肯定也会有一定的命名策略。对于增强类,是在基础类类名的基础上追加
$BySpringCGLIB
。具体可查看 Spring 中的 AbstractClassGenerator 中的 generateClassName 方法、 SpringNamingPolicy 类。
阶段2:Spring 扫描得到所有 @Bean 方法
Spring 会通过扫描拿到所有 Bean 的元数据。但这一步,不会生成实例。
阶段3:生成 Spring bean 实例
在 ConfigurationClassEnhancer 中生成cglib 增强类时使用了3个 interceptor: BeanMethodInterceptor 、BeanFactoryAwareMethodInterceptor、NoOp.INSTANCE 。
Spring 是通过执行 @Bean 注解的方法生成 bean,而执行方法时,会经过 cglib interceptor 。interceptor 内部则是基于 BeanFactory 去生成bean。
这种方式有两个特点:
- 调用
@Bean
注解的方法时,得到的是单例。 @Configuration
注解的类内部,@Bean
方法直接互相调用,得到的也是单例,因为这里用的是方法级的 interceptor (Method Interceptor)。