美文网首页
从零开始写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框架-(链式代理)

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