美文网首页
从零开始写Spring AOP框架-(链式代理)

从零开始写Spring AOP框架-(链式代理)

作者: d3f59bfc7013 | 来源:发表于2019-08-13 20:39 被阅读0次

Spring AOP的核心是Cglib和JDK的动态代理,那我们先写Spring AOP的前置增强和后置增强

示例代码链接

第一次尝试

我们对Greeting类进行前置和后置增强

public class Greeting {
    public void greet(String name){
        System.out.println("Hello,"+name);
    }
}

先写一个前置增强

public class BeforeProxy implements MethodInterceptor {
    public <T> T getProxy(Class<T> clazz) {
        return (T) Enhancer.create(clazz, this);
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        before();
        Object result=methodProxy.invokeSuper(o,objects);
        return result;
    }

    private void before() {
        System.out.println("call before");
    }
}

再写一个后置增强

public class AfterProxy implements MethodInterceptor {

    public <T> T getProxy(Class<T> clazz) {
        return (T) Enhancer.create(clazz, this);
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        Object result=methodProxy.invokeSuper(o,objects);
        after();
        return result;
    }

    private void after() {
        System.out.println("call after");
    }
}

应该就是这样写吧?先用 BeforeProxy 去增强 Greeting,得到一个代理对象beforeGreeting。然后再用 AfterProxy 去增强上一步得到的代理对象,得到一个新的代理对象 beforeAfterGreeting。最后将这个新的代理对象强制转型为目标类对象,并调用目标类对象的 greet() 方法。我们通过Client输出一下。

public class Client {
    public static void main(String args[]) {
        Greeting beforeGreeting= new BeforeProxy().getProxy(Greeting.class);
        Greeting beforeAfterGreeting=new AfterProxy().getProxy(beforeGreeting.getClass());
        beforeAfterGreeting.greet("gethin");
    }
}

mp69Wd.md.jpg

运行时报错!而且抛出了一个 net.sf.cglib.core.CodeGenerationException,可见这是 CGLib 的内部异常。遇到这种异常,一般都是很让人抓狂。看来 CGLib 自动生成的类,不能被自己再次增强了。如何解决呢?不妨借鉴 Servlet 的 Filter Chain的设计模式,它是“责任链模式”的一种变体,在 JavaEE 设计模式中命名为“拦截过滤器模式”。我们可以将每个 Proxy 用一根链子串起来,形成一个 Proxy Chain。然后调用这个 Proxy Chain,让它去依次调用 Chain 中的每个 Proxy。

第二次尝试

我们通过责任链模式,重新设计一下。
定义一个Proxy

public interface Proxy {
    Object doProxy(ProxyChain proxyChain);
}

编写代理链

public class ProxyChain {
    private Object targetObject;
    private MethodProxy methodProxy;
    private Object[] params;
    private Method method;
    List<Proxy> proxyList;
    private int currentIndex=0;

    public ProxyChain(Object targetObject, MethodProxy methodProxy, Object[] params, Method method, List<Proxy> proxyList) {
        this.targetObject = targetObject;
        this.methodProxy = methodProxy;
        this.params = params;
        this.method = method;
        this.proxyList = proxyList;
    }

    public Object doProxyChain() throws Throwable {
        Object result;
        if(currentIndex<proxyList.size()){
            result=proxyList.get(currentIndex++).doProxy(this);
        }else {
            result=methodProxy.invokeSuper(targetObject,params);
        }
        return result;
    }

    public Object getTargetObject() {
        return targetObject;
    }

    public MethodProxy getMethodProxy() {
        return methodProxy;
    }

    public Object[] getParams() {
        return params;
    }

    public Method getMethod() {
        return method;
    }

    public List<Proxy> getProxyList() {
        return proxyList;
    }
}

编写代理工厂类

public class ProxyFactory {
    public static <T> T createProxy(Class<T> tClass, final List<Proxy> proxyList){
       return (T) Enhancer.create(tClass, new MethodInterceptor() {
            public Object intercept(Object targetObject, Method originMethod, Object[] params, MethodProxy methodProxy) throws Throwable {
                return new ProxyChain(targetObject,methodProxy,params,originMethod,proxyList).doProxyChain();
            }
        });
    }
}

我们的目标不是为了实现 Proxy,而是为了实现 AOP。为了实现 AOP,采用了“模板方法模式”,弄一个 AbstractProxy 抽象类,让它去实现 Proxy 接口,并在其中定义方法调用模板,在需要横向拦截的地方,定义一些“钩子方法”。Spring 源码中大量使用了这一技巧。

public abstract class AbstractProxy implements Proxy {
    public Object doProxy(ProxyChain proxyChain) {
        Object targetObject = proxyChain.getTargetObject();
        Object[] params = proxyChain.getParams();
        MethodProxy methodProxy = proxyChain.getMethodProxy();
        Object result=null;
        begin();
        try {
            before(targetObject, params, methodProxy);
            result = proxyChain.doProxyChain();
            after(targetObject, params, methodProxy);
        } catch (Throwable throwable) {
            error(targetObject, params, methodProxy);
        }
        end();
        return result;
    }
    public void end() {
    }
    public void error(Object targetObject, Object[] params, MethodProxy methodProxy) {
    }
    public void after(Object targetObject, Object[] params, MethodProxy methodProxy) {
    }
    public void before(Object targetObject, Object[] params, MethodProxy methodProxy) {
    }
    public void begin() {

    }
}

重新编写前置类

public class BeforeProxy extends AbstractProxy {
    @Override
    public void before(Object targetObject, Object[] params, MethodProxy methodProxy) {
        System.out.println("call before");
    }
}

重新编写后置类

public class AfterProxy extends AbstractProxy {
    @Override
    public void after(Object targetObject, Object[] params, MethodProxy methodProxy) {
        System.out.println("call after");
    }
}

Client

public class Client6 {
    public static void main(String args[]) {
        BeforeProxy beforeProxy = new BeforeProxy();
        AfterProxy afterProxy = new AfterProxy();
        List<Proxy> proxyList = new ArrayList<Proxy>();
        proxyList.add(afterProxy);
        proxyList.add(beforeProxy);
        Student student = ProxyFactory.createProxy(Student.class, proxyList);
        student.sayHello();
    }
}

最终如愿输出结果

mCcAjs.md.jpg

相关文章

  • 从零开始写Spring AOP框架-(链式代理)

    Spring AOP的核心是Cglib和JDK的动态代理,那我们先写Spring AOP的前置增强和后置增强 示例...

  • AOP代理:

    AOP代理:AOP框架创建的对象,代理就是对目标对象的增强。Spring中的AOP代理可以是JDK动态代理,也可以...

  • spring aop 汇总

    静态代理、动态代理和cglib代理 aop 使用 Spring AOP - 注解方式使用介绍spring aop ...

  • 2018-03-21

    与AspectJ的静态代理不同,Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码...

  • Spring AOP源码解读1 - 程序入口

    前言 最近看了《从零开始写JavaWeb框架》,想比较一下Spring AOP的实现方式和书的上实现方式有什么不同...

  • Spring AOP 学习笔记(1) ---- 代理模式

    参考文章 spring aop 官方文档 掘金spring aop 教程 掘金动态代理 代理模式分类 根据代理类的...

  • Spring AOP 实现原理

    Spring AOP 实现原理 静态代理 众所周知 Spring 的 AOP 是基于动态代理实现的,谈到动态代理就...

  • 2018-01-31

    spring aop @(iJava)[spring framework] [toc] aop底层原理采用动态代理...

  • Spring AOP DefaultAdvisorAutoPro

    Spring AOP源码目录 Spring AOP源码01:Jdk动态代理底层源码Spring AOP源码02:P...

  • Spring学习系列--3.AOP

    Spring Aop Aop面向切面编程 Aop入门动态代理 动态代理,其实与Aop的原理有些相似,可以用动态代理...

网友评论

      本文标题:从零开始写Spring AOP框架-(链式代理)

      本文链接:https://www.haomeiwen.com/subject/kohijctx.html