Java AOP的实现原理和手写实现,支持JDK动态代理,Javassist代理,Cglib代理

Java AOP的实现原理和手写实现,支持JDK动态代理和Cglib代理

概述

面向切面编程已经在我们的平常工作中经常会用到, 平常我们在使用的都是使用spring封装的aop模块, 使用的时候只要配置几个注解就能实现逻辑了,非常的方便. 但是使用的方便也就意味着其封装的复杂, 另外spring的aop也是有其的演进,从最早的只能通过实现接口+xml配置,到现在@Aspect的支持来实现声明式的变成方式.

为什么要手写实现一遍

你能手写出来,自然证明你已经对其的很了解了, 那么再手写一遍更能加深你的印象, 下面我将会从原理介绍->类设计->接口设计->代码实现几个步骤来讲述手写的过程,顺便会讲一下我在写的过程中遇到的坑.

设计

下面是我设计的uml类图,因为受spring aop的设计实现,所以在命名上进行了一定程度的借鉴.

主要的接口设计是跟AOP的概念想对应的,比如pointcut对应切点,advice对应增强(也就是横切逻辑),ProxyFactory对应织入器

在这里插入图片描述

接口设计和实现

接口或者类的设计还是比较简单的,下面看一下具体的接口和实现

// 切点接口
public interface PointCut {
    Boolean match(Object object);
}
//目前就实现了切对应的类 和对应方法
public class MethodPointCut implements PointCut {
    private Method method;
...
    @Override
    public Boolean match(Object object) {
        return method.equals(object);
    }
}
public class ClassPointCut<T> implements PointCut{
    private Class<T> clazz;
   ...
    @Override
    public Boolean match(Object object){
        if (object.getClass().equals(clazz)) return true;
        for (Class<?> anInterface : object.getClass().getInterfaces()) {
            if (anInterface.equals(clazz)) return true;
        }
        return false;
    }
}

下面是横切逻辑的接口实现

//增强接口
public interface Advice {
}
//前置增强
public interface BeforeAdvice extends Advice{
    
    <T> void invokeBefore(Class<T> clazz, Method method, Object[] args);
}
public interface AroundAdvice extends Advice{
    // 注意这里使用了函数接口, 源方法的执行结果通过supplier.get() 进行获取结果
    <T>Object invoke(Class<T> clazz, Method method, Object[] args, Supplier<Object> supplier) throws Exception;
}
public interface AfterAdvice extends Advice {
    
    <T> Object invokeAfter(Class<T> clazz, Method method, Object[] args, Object result, Exception exception);
}

下面是用于汇聚切点和横切逻辑的类, 我实现了默认的实现,主要只是针对固定类和方法的aop增强

public interface Advisor {
}
// 这是默认的实现, 这个类主要是汇聚切点个横切逻辑的
public class DefaultAdvisor implements Advisor {
    //类必须要匹配的,不然就不需要进行代理了
    private ClassPointCut classPointCut;
    //在拦截方法时,如果不包含在内就不进行前后增强,如果为空就默认全部都要增强
    private List<MethodPointCut> methodPointCuts;
    //增强列表
    private List<Advice> adviceList;
    
    public DefaultAdvisor(ClassPointCut classPointCut) {
        this.classPointCut = classPointCut;
        this.methodPointCuts = new ArrayList<>();
        this.adviceList = new ArrayList<>();
    }
    
    /**
     * 构建横切逻辑调用链
     * @param supplier
     * @return
     */
    public AdviceChain buildChain(Supplier<Object> supplier) {
        AdviceChain adviceChain = new AdviceChain(supplier);
        for (Advice advice : adviceList) {
            if (advice instanceof BeforeAdvice) {
                adviceChain.addBeforeAdvice((BeforeAdvice) advice);
            }
            if (advice instanceof AroundAdvice) {
                adviceChain.addAroundAdvice((AroundAdvice) advice);
            }
            if (advice instanceof AfterAdvice) {
                adviceChain.addAfterAdvice((AfterAdvice) advice);
            }
        }
        return adviceChain;
    }
    
    /**
     * 添加方法切点,如果为空则默认拦截全部方法
     * @param methodPointCut
     * @return
     */
    public DefaultAdvisor addMethodPointCut(MethodPointCut methodPointCut) {
        methodPointCuts.add(methodPointCut);
        return this;
    }
    

    public DefaultAdvisor addAdvice(Advice advice) {
        adviceList.add(advice);
        return this;
    }
    
    /**
     * 判断是否需要构造代理对象
     *
     * @param object
     * @return
     */
    public Boolean matchClass(Object object) {
        return classPointCut == null || classPointCut.match(object);
    }
    
    /**
     * 判断是否需要拦截
     *
     * @param method
     * @return
     */
    public Boolean matchMethod(Method method) {
        if (methodPointCuts.isEmpty()) return true;
        for (MethodPointCut methodPointCut : methodPointCuts) {
            Boolean match = methodPointCut.match(method);
            if (match) return true;
        }
        return false;
    }
}

下面是一个比较重要的类,就是横切逻辑的链,也就是责任链模式的实现

public class AdviceChain {
    
    private List<BeforeAdvice> beforeAdvices;
    private List<AroundAdvice> aroundAdvices;
    private List<AfterAdvice> afterAdvices;
    private Supplier<Object> supplier;
    
    public AdviceChain( Supplier<Object> supplier) {
        this.beforeAdvices = new ArrayList<>();
        this.aroundAdvices =new ArrayList<>();
        this.afterAdvices =new ArrayList<>();
        this.supplier = supplier;
    }
    
    public void addBeforeAdvice(BeforeAdvice beforeAdvice){
        beforeAdvices.add(beforeAdvice);
    }
    public void addAroundAdvice(AroundAdvice aroundAdvice){
        aroundAdvices.add(aroundAdvice);
    
    }
    public void addAfterAdvice(AfterAdvice afterAdvice){
        afterAdvices.add(afterAdvice);
    }
    
    public <T>Object doInvoke(Class<T> clazz, Method method, Object[] objects){
    	//首先执行所有的前置增强
        beforeAdvices.forEach(e->e.invokeBefore(clazz, method, objects));
    
        Object object = null;
        Exception exception = null;
        // 最初生产者指向原方法的执行
        Supplier<Object> finalObjectSupplier = supplier;
        for (AroundAdvice aroundAdvice : aroundAdvices) {
            Supplier<Object> temp = finalObjectSupplier;
            //替换旧的给下一个AroundAdvice使用
            finalObjectSupplier = () -> {
                try {
                    return aroundAdvice.invoke(clazz, method, objects, temp);
                } catch (Exception e) {
                    return e;
                }
            };
        }
        //执行最后一个生成者
        Object result = finalObjectSupplier.get();
        if (result instanceof Exception) {
            exception = (Exception) result;
        } else {
            object = result;
        }
    
        Exception finalException = exception;
        Object finalObject = object;
        //后置增强的顺序执行
        afterAdvices.forEach(e->e.invokeAfter(clazz, method, objects, finalObject, finalException));
        
        return object;
    }
}

好了还剩下最后的织入器

public interface ProxyFactory {
    <T> T generateProxy(T target, Advisor advisor);
    
    default  <T> Object doInterceptor(T target, DefaultAdvisor advisor, Method method, Object[] args) throws IllegalAccessException, InvocationTargetException {
        String methodName = method.getName();
        Class<?>[] parameterTypes = method.getParameterTypes();
        if (method.getDeclaringClass() == Object.class) {
            return method.invoke(target, args);
        }
        if ("toString".equals(methodName) && parameterTypes.length == 0) {
            return target.toString();
        }
        if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
            return target.hashCode();
        }
        if ("equals".equals(methodName) && parameterTypes.length == 1) {
            return target.equals(args[0]);
        }
        
        if (!advisor.matchMethod(method)) return method.invoke(target, args);
        
        Supplier<Object> supplier = () -> {
            try {
                return method.invoke(target, args);
            } catch (Throwable throwable) {
                return new RuntimeException(throwable);
            }
        };
        AdviceChain adviceChain = advisor.buildChain(supplier);
        
        return adviceChain.doInvoke(target.getClass(), method, args);
    }
    
}

//jdk动态代理实现的织入器
public class JDKProxyFactory implements ProxyFactory {
    
    
    @Override
    public <T> T generateProxy(T target, Advisor advisor) {
        DefaultAdvisor defaultAdvisor = (DefaultAdvisor) advisor;
        if (!((DefaultAdvisor) advisor).matchClass(target)) return target;
    
        Object proxyInstance = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                target.getClass().getInterfaces(),
                (proxy, method, args) -> doInterceptor(target, (DefaultAdvisor) advisor, method, args));
        return (T)proxyInstance;
    
    }
    
   
}

//cglib实现逻辑类似
public class CglibProxyFactory implements ProxyFactory{
    
    
    @Override
    public <T>T generateProxy(T target , Advisor advisor){
        DefaultAdvisor defaultAdvisor = (DefaultAdvisor) advisor;
        if (!((DefaultAdvisor) advisor).matchClass(target)) return target;
        
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        // methodProxy.invokeSuper(o, objects);
        enhancer.setCallback((MethodInterceptor) (o, method, args, methodProxy) ->
                doInterceptor(target, (DefaultAdvisor) advisor, method, args));
    
        return (T)enhancer.create();
    }
    
}

// Javassist实现
public class JavassistProxyFactory implements ProxyFactory {
    
    
    @Override
    public <T> T generateProxy(T target, Advisor advisor) {
        DefaultAdvisor defaultAdvisor = (DefaultAdvisor) advisor;
        if (!((DefaultAdvisor) advisor).matchClass(target)) return target;
        
        
        javassist.util.proxy.ProxyFactory factory = new javassist.util.proxy.ProxyFactory();
        factory.setInterfaces(target.getClass().getInterfaces());
        Class<?> proxyClass = factory.createClass();
        ProxyObject javassistProxy;
        try {
            javassistProxy = (ProxyObject) proxyClass.newInstance();
            javassistProxy.setHandler((self, method, proceed, args) ->
                    doInterceptor(target, (DefaultAdvisor) advisor, method, args));
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        return (T) javassistProxy;
    }
    
}

这里提醒一下,之前写jdk动态代理的使用,没有使用target作为执行的对象,然后遇到了未知错误, 所以要千万注意,不能写的太快了, 然后cglib那里我将原来的执行改成了method.invoke, 是因为cglib的增强是支持方法嵌套增强的, 而jdk不支持, 所以为了统一就用method.invoke了, 另外cglib的底层是asm, javassist底层也是asm, 性能上的话我没有对比多.

测试

测试类代码如下

public interface Sleep {
    int sleep(int time);
}
public class SleepImpl  implements Sleep{
    @Override
    public int sleep(int time) {
        System.out.println(time);
        return time;
    }
}
public class MainTest {
    
    public static void main(String[] args) {
        Sleep sleep = new SleepImpl();
    
        DefaultAdvisor advisor = new DefaultAdvisor(new ClassPointCut(Sleep.class)).addAdvice(new BeforeAdvice() {
            @Override
            public <T> void invokeBefore(Class<T> clazz, Method method, Object[] args) {
                System.out.println("before");
            }
        }).addAdvice(new AfterAdvice() {
            @Override
            public <T> Object invokeAfter(Class<T> clazz, Method method, Object[] args, Object result, Exception exception) {
                System.out.println("after");
                return result;
            }
        }).addAdvice(new AroundAdvice() {
            @Override
            public <T> Object invoke(Class<T> clazz, Method method, Object[] args, Supplier<Object> supplier) throws Exception {
                System.out.println("around before");
                Object result = supplier.get();
                System.out.println("around after");
                return result;
            }
        }).addAdvice(new AroundAdvice() {
            @Override
            public <T> Object invoke(Class<T> clazz, Method method, Object[] args, Supplier<Object> supplier) throws Exception {
                System.out.println("around before2");
                Object result = supplier.get();
                System.out.println("around after2");
                return result;
            }
        });
    
        ProxyFactory proxyFactory = new JavassistProxyFactory();
//        ProxyFactory proxyFactory = new JDKProxyFactory();
//        ProxyFactory proxyFactory = new CglibProxyFactory();
    
        Sleep sleep1 = proxyFactory.generateProxy(sleep, advisor);
    
        sleep1.sleep(100);
    
    }
}

执行的结果如下

before
around before2
around before
100
around after
around after2
after
Process finished with exit code 0

可以看到执行的结果就是我想要的,进行aop增强后的结果, 虽然使用的时候用没有 spring的aop那么好用,但是实际上spring在启动的时候也会将基于注解的aop逻辑进行转换成具体的类, 所以让我们用的时候才会这么简单, 有了上面的这一套代码,就可以做很多的事情了,比如自己实现以个声明式的事务管理, 方法参数的日志打印等,都是可以的.

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值