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

2019-08-13  本文已影响0人  d3f59bfc7013

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
上一篇下一篇

猜你喜欢

热点阅读