@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 在方法调用前添加逻辑
System.out.println("Before method call: " + method.getName());
/**
* 用子类对象作为目标对象
* Before method call: doSomething
* Doing something...
* Before method call: doB
* doing B
* After method call: doB
* After method call: doSomething
*/
// 执行原方法,非反射调用
Object result = proxy.invokeSuper(obj, args);
/**
* 用target作为目标对象,
* Before method call: doSomething
* Doing something...
* doing B
* After method call: doSomething
*/
// 非反射调用
// Object result = proxy.invoke(myclass,args);
// 反射调用
// Object result = method.invoke(myclass,args);
// 在方法调用后添加逻辑
System.out.println("After method call: " + method.getName());
return result;
}
ConfigurationClassEnhancer
是Spring框架中用于增强 @Configuration
类的关键组件。它通过CGLIB库生成 @Configuration
类的代理对象,确保所有的 @Bean
方法调用都由Spring容器管理。下面是 ConfigurationClassEnhancer
的详细解析,包括其工作原理和内部机制。
工作原理
-
类扫描和注册:
- Spring启动时,会扫描应用程序中的所有类,寻找带有
@Configuration
注解的类。 - 这些类会被注册到Spring容器中,并标记为配置类。
- Spring启动时,会扫描应用程序中的所有类,寻找带有
-
代理生成:
ConfigurationClassEnhancer
负责生成@Configuration
类的代理对象。- 使用CGLIB库生成代理类,代理类继承自
@Configuration
类。
-
方法拦截:
- 生成的代理类会重写
@Configuration
类中的所有方法。 - 每个方法都会被重写为一个拦截方法,这些方法会在调用时委托给Spring容器。
- 生成的代理类会重写
-
Bean 创建和管理:
- 当Spring容器需要创建某个Bean时,会通过代理对象调用相应的
@Bean
方法。 - 拦截器会确保这些调用是由Spring容器管理的,从而可以正确地处理单例模式、作用域、依赖注入等特性。
- 当Spring容器需要创建某个Bean时,会通过代理对象调用相应的
内部机制
1. 代理生成
ConfigurationClassEnhancer
使用CGLIB库生成代理类。CGLIB通过继承的方式生成代理类,代理类继承自 @Configuration
类。
public class ConfigurationClassEnhancer {
private final Class<?> configClass;
private final BeanFactory beanFactory;
public ConfigurationClassEnhancer(Class<?> configClass, BeanFactory beanFactory) {
this.configClass = configClass;
this.beanFactory = beanFactory;
}
public Object enhance() {
// 使用CGLIB生成代理类
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(configClass);
enhancer.setCallback(new ConfigurationClassEnhancerCallback(beanFactory));
return enhancer.create();
}
}
2. 方法拦截
ConfigurationClassEnhancerCallback
是一个实现了 MethodInterceptor
接口的类,用于拦截 @Bean
方法的调用。
public class ConfigurationClassEnhancerCallback implements MethodInterceptor {
private final BeanFactory beanFactory;
public ConfigurationClassEnhancerCallback(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 获取方法名
String methodName = method.getName();
// 检查是否是 @Bean 方法
if (method.isAnnotationPresent(Bean.class)) {
// 从Spring容器中获取Bean
String beanName = method.getAnnotation(Bean.class).name();
if (beanName.isEmpty()) {
beanName = Introspector.decapitalize(methodName);
}
return beanFactory.getBean(beanName);
} else {
// 如果不是 @Bean 方法,直接调用原方法
return proxy.invokeSuper(obj, args);
}
}
}
示例代码
假设我们有一个简单的 @Configuration
类:
@Configuration
public class AppConfig {
@Bean
public BeanA beanA() {
System.out.println("Creating BeanA with BeanB");
return new BeanA(beanB());
}
@Bean
public BeanB beanB() {
System.out.println("Creating BeanB");
return new BeanB();
}
}
在Spring容器中配置这个类:
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
BeanA beanA = context.getBean(BeanA.class);
context.close();
}
}
输出
运行上述代码,输出将是:
Creating BeanB
Creating BeanA with BeanB
详细步骤
-
类扫描和注册:
- Spring启动时,扫描到
AppConfig
类并注册为一个Bean定义。
- Spring启动时,扫描到
-
代理生成:
ConfigurationClassEnhancer
使用CGLIB生成AppConfig
类的代理对象。- 代理对象会重写
beanA()
和beanB()
方法,使其成为拦截方法。
-
方法拦截:
- 当通过代理对象调用
beanA()
方法时,ConfigurationClassEnhancerCallback
拦截器会检查是否需要创建一个新的Bean。 - 拦截器调用
beanB()
方法,这个调用也会通过代理对象进行。
- 当通过代理对象调用
-
Bean 创建和管理:
beanB()
方法被调用,创建并返回BeanB
实例。beanA()
方法被调用,创建并返回BeanA
实例,同时注入beanB()
方法创建的BeanB
实例。
内部机制总结
-
代理生成:
ConfigurationClassEnhancer
使用CGLIB生成@Configuration
类的代理对象。- 代理对象继承自
@Configuration
类,并重写所有方法。
-
方法拦截:
ConfigurationClassEnhancerCallback
实现MethodInterceptor
接口,拦截对@Bean
方法的调用。- 拦截器检查方法调用,确保通过Spring容器管理。
-
Bean 创建和管理:
- 当Spring容器需要创建某个Bean时,会通过代理对象调用相应的
@Bean
方法。 - 拦截器调用Spring容器的方法来创建和管理Bean。
- 当Spring容器需要创建某个Bean时,会通过代理对象调用相应的
通过这种方式,Spring确保了 @Configuration
类中的所有 @Bean
方法调用都由Spring容器管理,从而实现了灵活和强大的Bean管理机制。