本文针对的是icomac-spring项目,是自己重现了tianxiaono的仿写toy-spring项目,最开始的版本是黄亿华前辈实现的 tiny-spring ,该项目时间节点是 2014.1
具体参考:自己动手实现的 Spring IOC 和 AOP - 下篇
AOP 原理
AOP 是基于动态代理模式实现的,具体实现上可以基于 JDK 动态代理或者 Cglib 动态代理。其中 JDK 动态代理只能代理实现了接口的对象,而 Cglib 动态代理则无此限制。所以在为没有实现接口的对象生成代理时,只能使用 Cglib。在 icomac-spring 项目中,暂时只实现了基于 JDK 动态代理的代理对象生成器。
关于 AOP 原理这里就不多说了,下面说说 icomac-spring 中 AOP 的实现步骤。还是像上面一样,先列流程:
- AOP 逻辑介入 BeanFactory 实例化 bean 的过程
- 根据 Pointcut 定义的匹配规则,判断当前正在实例化的 bean 是否符合规则
- 如果符合,代理生成器将切面逻辑 Advice 织入 bean 相关方法中,并为目标 bean 生成代理对象
- 将生成的 bean 的代理对象返回给 BeanFactory 容器,到此,AOP 逻辑执行结束
对于上面的4步流程,熟悉 Spring AOP 的朋友应该能很容易理解。如果有朋友不理解也没关系,在后续章节,我会详细介绍相关流程的具体实现。
基于 JDK 动态代理的 AOP 实现
本节说说基于 JDK 动态代理的代理对象生成器具体实现。在 icomac-spring 项目中,代理对象生成器的逻辑主要写在了 JdkDynamicAopProxy 类中,这个类的有两个方法,其中 getProxy 方法用于生成代理对象。invoke 方法是 InvocationHandler 接口的具体实现,包含了将通知(Advice)织入相关方法中,是上面所列流程中第3步流程的具体实现。
JdkDynamicAopProxy 实现代码:
package com.icomac.spring.aop;
import org.aopalliance.intercept.MethodInterceptor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 基于 JDK 动态代理的代理对象生成器
* Created by icomac on 19/4/10.
*/
final public class JdkDynamicAopProxy extends AbstractAopProxy implements InvocationHandler {
public JdkDynamicAopProxy(AdvisedSupport advised) {
super(advised);
}
/**
* 为目标 bean 生成代理对象
*
* @return bean 的代理对象
*/
@Override
public Object getProxy() {
return Proxy.newProxyInstance(getClass().getClassLoader(),
advised.getTargetSource().getInterfaces(), this);
}
/**
* InvocationHandler 接口中的 invoke 方法具体实现,封装了具体的代理逻辑
*
* @param proxy
* @param method
* @param args
* @return 代理方法或原方法的返回值
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodMatcher methodMatcher = advised.getMethodMatcher();
// 使用方法匹配器 methodMatcher 测试 bean 中原始方法 method 是否符合匹配规则
if (methodMatcher != null && methodMatcher.matchers(method,
advised.getTargetSource().getTargetClass())) {
// 获取 Advice。MethodInterceptor 的父接口继承了 Advice
MethodInterceptor methodInterceptor = advised.getMethodInterceptor();
// 将 bean 的原始 method 封装成 MethodInvocation 实现类对象,
// 将生成的对象传给 Adivce 实现类对象,执行通知逻辑
return methodInterceptor.invoke(
new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(), method, args));
} else {
// 当前 method 不符合匹配规则,直接调用 bean 中的原始 method
return method.invoke(advised.getTargetSource().getTarget(), args);
}
}
}
下面用个流程图对通知织入逻辑进行总结:
最后对 JdkDynamicAopProxy 进行简单的测试,测试代码及结果如下
测试类
package com.icomac.spring.aop;
import com.icomac.spring.HelloService;
import com.icomac.spring.HelloServiceImpl;
import com.icomac.spring.aop.AdvisedSupport;
import com.icomac.spring.aop.JdkDynamicAopProxy;
import com.icomac.spring.aop.TargetSource;
import org.junit.Test;
import java.lang.reflect.Method;
/**
* 对JdkDynamicAopProxy进行测试
* Created by icomac on 19/4/10.
*/
public class JdkDynamicAopProxyTest {
@Test
public void getProxy() throws Exception {
System.out.println("---------- no proxy ----------"); //无代理
HelloService helloService = new HelloServiceImpl(); //目标对象实例化
helloService.sayHelloWorld();
System.out.println("\n----------- proxy -----------"); //启动代理
AdvisedSupport advisedSupport = new AdvisedSupport(); //实例化advisedSupport(集合目标对象以及方法拦截器和匹配法则)
advisedSupport.setMethodInterceptor(new LogInterceptor()); //添加方法拦截器,相当于织入执行通知
//目标资源类(这集合了目标对象以及类和接口)实例化
TargetSource targetSource = new TargetSource(
helloService, HelloServiceImpl.class, HelloServiceImpl.class.getInterfaces());
advisedSupport.setTargetSource(targetSource); //添加目标对象
advisedSupport.setMethodMatcher((Method method, Class beanClass) -> true); //添加匹配法则
//advisedSupport获得代理,并生成代理对象helloService
helloService = (HelloService) new JdkDynamicAopProxy(advisedSupport).getProxy();
helloService.sayHelloWorld();
}
}
测试结果