前言
在之前的文章 # 通过手写aop来聊聊切点表达式那些事 我们了解aop的表达式如何完成匹配的,那么这篇文章我们就来聊聊如何实现一个aop
包装一个切面通知信息
什么是切面通知信息,他是做什么的?
说白了就是将我们AOP中所需要的目标对象,方法匹配器,方法拦截器,同一整合到一个类中。这样我们后续实现代理类的时候,就可以通过关联关系(通俗的理解就是作为代理类的一个成员变量)
使用这个切面通知信息类。
切面通知信息成员属性介绍
我们首先来看看笔者实现的切面通知信息类,实现也很简单,一个目标对象类TargetSource,一个方法匹配器MethodMatcher,一个方法拦截器methodInterceptor,我们不妨看看这每个成员变量的具体实现
package cn.shark.springframework.aop;
import org.aopalliance.intercept.MethodInterceptor;
/**
* 将目标、拦截器、表达式全部集成到一个类中,方便代理使用这些工具
*/
public class AdvisedSupport {
/**
* 目标对象
*/
private TargetSource targetSource;
/**
* 方法匹配器
*/
private MethodMatcher methodMatcher;
// 拦截器
private MethodInterceptor methodInterceptor;
private boolean proxyTargetClass;
get()/set()....
}
复制代码
targetsource其实做的也很简单,无法是将目标对象包装一层,考虑到后续jdk代理需要用到类对象的接口信息,所以封装了一个getTargetClass方法
public class TargetSource {
private final Object target;
public TargetSource(Object target) {
this.target = target;
}
public Class<?>[] getTargetClass(){
//它能够获得这个对象所实现的所有接口
return target.getClass().getInterfaces();
}
public Object getTarget() {
return target;
}
}
复制代码
MethodMatcher
/**
* 方法匹配器
*/
public interface MethodMatcher {
/**
* 判断当前类的方法是否匹配
* @param method
* @param targetClass
* @return
*/
boolean matches(Method method,Class<?> targetClass);
}
复制代码
MethodInterceptor
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.aopalliance.intercept;
public interface MethodInterceptor extends Interceptor {
Object invoke(MethodInvocation var1) throws Throwable;
}
复制代码
代理对象
定义一个代理对象接口
我们后续代理的方式可能多种多样,那么我们就是用一个接口同一他们的动作,并且方便其他类使用无需关联具体而是关联抽象(通俗来说就是用接口作为成员成员变量起到解耦的作用)
/**
* AopProxy 是代理的抽象对象,它的实现主要是基于 JDK 的代理和 Cglib 代理。
*/
public interface AopProxy {
Object getProxy();
}
复制代码
jdk代理对象的设计与实现
看看下方的代码,实现逻辑也很简单,如果方法匹配则进行方法拦截,反之直接反射调用。但是我们看到了在方法拦截器的传参是一个ReflectiveMethodInvocation,这到底是什么呢?我们不妨步进看看
public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {
private final AdvisedSupport advisedSupport;
public JdkDynamicAopProxy(AdvisedSupport advisedSupport) {
this.advisedSupport = advisedSupport;
}
@Override
public Object getProxy() {
// 因为继承了InvocationHandler 所以就可以用this作为第三个参数
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),advisedSupport.getTargetSource().getTargetClass(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (advisedSupport.getMethodMatcher().matches(method,advisedSupport.getTargetSource().getTargetClass().getClass())){
MethodInterceptor methodInterceptor = advisedSupport.getMethodInterceptor();
return methodInterceptor.invoke(new ReflectiveMethodInvocation(advisedSupport.getTargetSource().getTarget(),method,args));
}
return method.invoke(advisedSupport.getTargetSource().getTarget(),args);
}
}
复制代码
可以看到,该类无法是一个继承MethodInvocation且包装了目标对象,目标对象方法,目标对象方法参数的一个类而已。这么做的好处只有一个,由于拦截器invoke需要的数据需要用MethodInvocation类型,所以我们就继承他然后自己实现一个这样的类出来并将需要的参数set进去。
/**
* 本质上就是一个对目标对象、目标对象方法、目标对象参数的一个包装,仅此而已
*/
public class ReflectiveMethodInvocation implements MethodInvocation {
protected Object target;
protected Method method;
protected Object[] args;
public ReflectiveMethodInvocation(Object target, Method method, Object[] args) {
this.target = target;
this.method = method;
this.args = args;
}
get()/set()
}
复制代码
CGLIB代理对象的设计与实现
CGLIB的getProxy实现与jdk代理有所区别,因为cglib使用的Enhancer类可以在运行期间为接口使用底层的ASM字节码增强技术生成对象,所以代理对象不需要继承任何接口。
我们注意到Cglib的getProxy中创建代理类的enhancer使用setSuperclass、setInterfaces完成设置目标对象和目标对象所有的接口。再用setCallback设置一个DynamicAdvisedInterceptor即动态拦截器,我们不妨步进看看这具体是什么东西
public class Cglib2AopProxy implements AopProxy {
private final AdvisedSupport advisedSupport;
public Cglib2AopProxy(AdvisedSupport advisedSupport) {
this.advisedSupport = advisedSupport;
}
@Override
public Object getProxy() {
// 基于 Cglib 使用 Enhancer 代理的类可以在运行期间为接口使用底层 ASM 字节码增强技术处理对象的代理对象生成,因此被代理类不需要实现任何接口。
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(advisedSupport.getTargetSource().getTarget().getClass());
enhancer.setInterfaces(advisedSupport.getTargetSource().getTargetClass());
enhancer.setCallback(new DynamicAdvisedInterceptor(advisedSupport));
return enhancer.create();
}
private static class DynamicAdvisedInterceptor implements MethodInterceptor {
private AdvisedSupport advisedSupport;
public DynamicAdvisedInterceptor(AdvisedSupport advisedSupport) {
this.advisedSupport = advisedSupport;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
CglibMethodInvocation cglibMethodInvocation = new CglibMethodInvocation(advisedSupport.getTargetSource().getTarget(),method,objects,methodProxy);
if (advisedSupport.getMethodMatcher().matches(method,advisedSupport.getTargetSource().getTarget().getClass())){
return advisedSupport.getMethodInterceptor().invoke(cglibMethodInvocation);
}
return cglibMethodInvocation.proceed();
}
}
private static class CglibMethodInvocation extends ReflectiveMethodInvocation {
private final MethodProxy methodProxy;
public CglibMethodInvocation(Object target, Method method, Object[] args, MethodProxy MethodProxy) {
super(target, method, args);
this.methodProxy = MethodProxy;
}
/**
* 因为是cglib的远古继承ReflectiveMethodInvocation重写proceed,使用自己的代理完成方法调用
* @return
* @throws Throwable
*/
@Override
public Object proceed() throws Throwable {
return methodProxy.invoke(this.target, this.args);
}
}
}
复制代码
可以看到他是cglib代理的一个内部类,继承了MethodInterceptor实现拦截逻辑。我们注意到这里的方法拦截器调用了一个cglib自己的实现的方法调用器cglibMethodInvocation,我们不妨看看他的实现
private static class DynamicAdvisedInterceptor implements MethodInterceptor {
private AdvisedSupport advisedSupport;
public DynamicAdvisedInterceptor(AdvisedSupport advisedSupport) {
this.advisedSupport = advisedSupport;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
CglibMethodInvocation cglibMethodInvocation = new CglibMethodInvocation(advisedSupport.getTargetSource().getTarget(),method,objects,methodProxy);
if (advisedSupport.getMethodMatcher().matches(method,advisedSupport.getTargetSource().getTarget().getClass())){
return advisedSupport.getMethodInterceptor().invoke(cglibMethodInvocation);
}
return cglibMethodInvocation.proceed();
}
}
复制代码
不过如此,只不过继承了ReflectiveMethodInvocation,将proceed逻辑改为cglib反射调用方法的形式而已
private static class CglibMethodInvocation extends ReflectiveMethodInvocation {
private final MethodProxy methodProxy;
public CglibMethodInvocation(Object target, Method method, Object[] args, MethodProxy MethodProxy) {
super(target, method, args);
this.methodProxy = MethodProxy;
}
/**
* 因为是cglib的远古继承ReflectiveMethodInvocation重写proceed,使用自己的代理完成方法调用
* @return
* @throws Throwable
*/
@Override
public Object proceed() throws Throwable {
return methodProxy.invoke(this.target, this.args);
}
}
复制代码
用一个类图总结一下上述的设计结构
用一个测试用例来走一遍代码全流程
代码
一个userService接口
public interface IUserService {
String queryUserInfo();
}
复制代码
其实现类
public class UserService implements IUserService {
private String uId;
private String company;
private String location;
private UserDao userDao;
private ApplicationContext applicationContext;
private BeanFactory beanFactory;
public String queryUserInfo() {
try {
Thread.sleep(new Random(1).nextInt(100));
} catch (InterruptedException e) {
e.printStackTrace();
}
return "89757 鲨鱼辣椒 福建";
}
}
复制代码
测试用例
/**
* 测试还没整合到spring的aop
* @throws NoSuchMethodException
*/
@Test
public void testAopWithoutSpring() throws NoSuchMethodException {
IUserService userService=new UserService();
// 创建通知信息对象
AdvisedSupport advisedSupport=new AdvisedSupport();
// 设置目标对象
advisedSupport.setTargetSource(new TargetSource(userService));
// 设置方法拦截器
advisedSupport.setMethodInterceptor(new UserServiceInterceptor());
// 设置匹配表达式对象
advisedSupport.setMethodMatcher(new AspectJExpressionPointcut("execution(* cn.shark.springframework.bean.IUserService.*(..))"));
// 代理对象(JdkDynamicAopProxy)
IUserService proxy_jdk = (IUserService) new JdkDynamicAopProxy(advisedSupport).getProxy();
// 测试调用
System.out.println("测试结果:" + proxy_jdk.queryUserInfo());
// 代理对象(Cglib2AopProxy)
IUserService proxy_cglib = (IUserService) new Cglib2AopProxy(advisedSupport).getProxy();
// 测试调用
System.out.println("测试结果:" + proxy_cglib.queryUserInfo());
}
复制代码
通过图解debug走一遍自己实现的AOP
以jdk作为代理走读一遍
首先jdk代理初始化
通过切面通知信息各种成员属性进行赋值,并将自己作为方法拦截器作为参数InvocationHandler传入
创建好代理类后开始使用代理类调用被代理类的方法
走到jdk代理自己继承InvocationHandler而编写的拦截逻辑
为MethodInvocation初始化
拿到方法拦截器调用方法调用器
打完收工
下一篇笔者会将其整合到自研spring框架中