+ Spring AOP 如何创建代理 beans +
+ + +Spring AOP 是基于代理实现的,它既支持 JDK 动态代理也支持 CGLib。
+-
+
- 在什么时候创建代理对象的? +
- 怎么创建代理对象的? +
过程简单图解
+ +准备工作
-
+
- 引入依赖
1
2
3
4
5
6
7
8
9
10<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
+ - 目标对象类
1
2
3
4
5
6public class MathCalculator {
public int div(int i, int j) {
return i / j;
}
}
+ - 切面类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class LogAspects {
public void pointCut() {
}
public void logStart(JoinPoint joinPoint) {
System.out.println(joinPoint.getSignature().getName() + "除法运行@Before。。。参数列表为 " + Arrays.asList(joinPoint.getArgs()) + "");
}
public void logEnd(JoinPoint joinPoint) {
System.out.println(joinPoint.getSignature().getName() + "除法结束@After。。。");
}
public void logReturn(JoinPoint joinPoint, Object result) {
System.out.println(joinPoint.getSignature().getName() + "除法正常返回@AfterReturning。。。运行结果 " + result);
}
public void logException(JoinPoint joinPoint, Exception e) {
System.out.println(joinPoint.getSignature().getName() + "除法异常@AfterThrowing。。。异常信息 " + e.getMessage());
}
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println(joinPoint.getSignature().getName() + " @Around开始");
Object proceed = joinPoint.proceed();
System.out.println(joinPoint.getSignature().getName() + " @Around结束");
return proceed;
}
}
+ - 配置类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class AopConfig {
public MathCalculator mathCalculator() {
return new MathCalculator();
}
public LogAspects logAspects() {
return new LogAspects();
}
}
+ - 测试类
1
2
3
4
5
6
7
8
9
10
11public class AopTest {
public void aopTest() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AopConfig.class);
MathCalculator mathCalculator = ac.getBean(MathCalculator.class);
mathCalculator.div(1, 1);
mathCalculator.div(1, 0);
ac.close();
}
}
+ - Debug 断点的判断条件(可选)
1
beanName.equals("mathCalculator")
+
创建代理 Bean 和创建普通 Bean 的区别
其实创建代理 Bean 的过程和创建普通 Bean 的过程直到进行初始化处理(initializeBean)前都是一样的。更具体地说,如很多资料所言,Spring 创建代理对象的工作,是在应用后置处理器阶段完成的。
+常规的入口 getBean
mathCalculator 以 getBean 方法为起点,开始创建的过程。
+1 |
|
应用后置处理器
在正常地实例化 Bean 后,初始化 Bean 时,会对 Bean 实例应用后置处理器。
+可是,究竟是哪一个后置处理器做的呢?
+1 | protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) { |
AnnotationAwareAspectJAutoProxyCreator
在本示例中,创建代理的后置处理器就是 AnnotationAwareAspectJAutoProxyCreator,它继承自 AbstractAutoProxyCreator,AbstractAutoProxyCreator 实现了 BeanPostProcessor 接口。
+那么,它是什么时候,怎么加入到 beanFactory 中呢?
+PS: 显然,还有其他继承自 AbstractAutoProxyCreator 的后置处理器,暂时不谈。
+BeanPostProcessor 的方法
postProcessBeforeInitialization 和 postProcessAfterInitialization 方法,前者什么都没做,后者在必要时对 Bean 进行包装。
+-
+
AbstractAutoProxyCreator#postProcessAfterInitialization
就是创建代理对象的入口。
+- wrapIfNecessary 就是将 Bean 包装成代理 Bean 的入口方法。 +
1 | public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport |
创建代理 Bean 的过程
按需包装成代理 wrapIfNecessary
1 | protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { |
AbstractAutoProxyCreator 视角,创建代理
AbstractAutoProxyCreator#createProxy,创建一个 ProxyFactory,将工作交给它处理。
+-
+
- 创建一个代理工厂 ProxyFactory +
- 设置相关信息 +
- 通过 ProxyFactory 获取代理 +
1 | protected Object createProxy( |
ProxyFactory 视角,获取代理
ProxyFactory#getProxy,创建一个 AopProxy 并委托它实现 getProxy。
+++AopProxy 的含义与职责从字面上有点不好理解。
+
1 | public Object getProxy(ClassLoader classLoader) { |
ProxyFactor视角,创建 AopProxy
ProxyFactory#createAopProxy,获取一个 AopProxyFactory 创建 AopProxy。
+1 | protected final synchronized AopProxy createAopProxy() { |
AopProxyFactory视角,创建 AopProxy
AopProxyFactory#createAopProxy。
+-
+
- AopProxyFactory 有且仅有一个默认实现 DefaultAopProxyFactory。 +
- createAopProxy 方法会根据配置信息,返回具体实现:开箱即用的有 JdkDynamicAopProxy 或者 ObjenesisCglibAopProxy。 +
这里的处理,决定了 Spring AOP 会使用哪一种动态代理实现。比如 Spring AOP 默认使用 JDK 动态代理,如果目标对象实现了接口 Spring 会使用 JDK 动态代理,这些结论的依据就在于此。
+1 | public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { |
获取代理 AopProxy#getProxy
AopProxy 视角,获取代理。
+JDK 动态代理
JdkDynamicAopProxy。
+1 |
|
InvocationHandler 的 invoke 方法
根据 Proxy.newProxyInstance(classLoader, proxiedInterfaces, this)
可知,this 也就是 JdkDynamicAopProxy 同时也是一个 InvocationHandler,它必然实现了 invoke 方法,当代理对象调用方法时,就会进入到 invoke 方法中。
1 |
|
CGLib 动态代理
ObjenesisCglibAopProxy。
+1 |
|
为什么 Spring 中没有依赖 CGLib
你可能会注意到 Spring 中并没有直接依赖 CGLib,像 Enhancer 所在的包是 org.springframework.cglib.proxy
。根据文档:
++从 spring 3.2 开始,不再需要将 cglib 添加到类路径中,因为 cglib 类在 org.springframework 下重新打包并分布在 spring-core jar 中。 这样做既是为了方便,也是为了避免与使用不同版本 cglib 的其他项目发生潜在冲突。
+
创建代理前的准备
在前面预留了一些问题,当初我在看网上的资料时就有这些困惑。
+Bean 后置处理器 AspectJAwareAdvisorAutoProxyCreator 在什么时候,怎么加入到 beanFactory 中的?
Debug 停留在 Spring 上下文刷新方法中的 finishBeanFactoryInitialization。
+1 |
|
从 beanFatory 的 beanDefinitionMap 可以观察到,配置类 AopConfig 中的 MathCalculator 和 LogAspect 的信息已经就位。
+ + +从 beanFactory 的 beanProcessor 可以观察到,AnnotationAwareAspectJAutoProxyCreator 已经就位。
+ + +@EnableXXX 的魔法
注解 @EnableXXX 往往伴随着注解 @Import,在 invokeBeanFactoryPostProcessors(beanFactory) 中,工厂后置处理器 ConfigurationClassPostProcessor 会处理它。
+1 |
|
在 ConfigurationClassPostProcessor 的处理中,因为 AspectJAutoProxyRegistrar 实现了 ImportBeanDefinitionRegistrar,registerBeanDefinitions 方法会被调用,AnnotationAwareAspectJAutoProxyCreator 的 beanDefinition 随之被注册到 beanFactory,因 AnnotationAwareAspectJAutoProxyCreator 实现了 BeanPostProcessor 被提前创建。
+1 | class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { |
1 | public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) { |
切面类 LogAspect 的解析是在什么时候?
进入创建 Bean 的方法 createBean 后,除了 doCreateBean,应额外留意 resolveBeforeInstantiation 方法。
+-
+
Object bean = resolveBeforeInstantiation(beanName, mbdToUse)
,在实例化前进行解析。
+Object beanInstance = doCreateBean(beanName, mbdToUse, args)
,创建 Bean 的具体过程。
+
1 |
|
入口方法 resolveBeforeInstantiation
根据注释,该方法给 BeanPostProcessors 一个机会提前返回一个代理对象。在本示例中,返回 null,但是方法在第一次执行后已经提前解析得到 advisors 并缓存。
+1 | protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) { |
InstantiationAwareBeanPostProcessor
应用 InstantiationAwareBeanPostProcessor 的 postProcessBeforeInstantiation。
+1 | protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) { |
AnnotationAwareAspectJAutoProxyCreator 不仅仅是一个 BeanPostProcessor,它还是一个 InstantiationAwareBeanPostProcessor。
+1 | public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { |
和 wrapIfNecessary 方法对比,容易发现两者有不少相似的处理。
+ + +++注意:以下方法应注意是否被子类重写。
+
org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator#shouldSkip
+1 | protected boolean shouldSkip(Class<?> beanClass, String beanName) { |
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean
+1 | protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) { |
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisors
+1 | protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { |
容易注意到两者在创建代理前,都会调用 findCandidateAdvisors 方法查找候选的 advisors,其实这也是我们想要找的对切面类的解析处理所在。
+查找并缓存 advisors
org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
+1 | protected List<Advisor> findCandidateAdvisors() { |
org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors
+1 | public List<Advisor> buildAspectJAdvisors() { |
可以通过 beanFactory->beanPostProcessors->aspectJAdvisorsBuilder->advisorsCache
观察 advisors 的查找情况。