zoukankan      html  css  js  c++  java
  • Jdk动态代理个人简单梳理

    java动态代理在Spring的AOP中可谓是被应用到了极致,一直不是很清楚,今天想复习一下设计模式,刚好看到动态代理一下就把我的思绪拉回到看AOP源码的时光了,说实话动态代理我用的太少了,于是今天小总结一下,来看看。

    引入如下场景:房东想租房子,但是他只想租不想管其余的琐事,于是他找中介,把房子托给他,这个中介就是一个代理者。

    静态代理,十分简单:就是代理者内部聚合一个接口,这个接口是房东和中介共有的,这样就实现了静态的代理,这里就不再赘述了,代码贴出来看一眼就懂了。

    // 被代理类和代理类共同的操作
    interface Action {
        default void doOther() {
        };
    
        void display();
    }
    
    // 被代理类【房东】
    class Host implements Action {
    
        @Override
        public void display() {
            System.out.println("我是房东,我只想租房子,啥也不想管");
        }
    }
    
    // 代理类【中介】
    class HostProxy implements Action {
        private Action action;
    
        public HostProxy() {
            action = new Action() {
                @Override
                public void display() {
                    System.out.println("do nothing...");
                }
            };
        }
    
        public HostProxy(Action action) {
            this.action = action;
        }
    
        @Override
        public void display() {
            PostProcessorsBeforeAction();
            action.display();
            PostProcessorsAfterAction();
        }
    
        private void PostProcessorsBeforeAction() {
            System.out.println("我来代理你做吧");
        }
    
        private void PostProcessorsAfterAction() {
            System.out.println("代理执行后序到结束");
        }
    }
    

    动态代理:

    // 动态代理雏形...
    Action host = new Host();
    InvocationHandler invocationHandler = new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("动态代理之前干事情");
            host.display();
            System.out.println("动态代理完成");
            return null;
        }
    };
    Action actionProxy = (Action) Proxy.newProxyInstance(Action.class.getClassLoader(), new Class[]{Action.class}, invocationHandler);
    actionProxy.display();
    

    个人写动态代理【简单版,有时间继续探讨】:

    // 自己写一下动态代理
    class DynamicProxy<T> {
        public T getProxy(Class<?> clazz, T obj, Object... args){
            InvocationHandler invocationHandler = new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("动态代理之前干的...事情");
                    // 原方法调用(这里只测试有一个方法,我取出第一个就好)
                    // Method[] methods = obj.getClass().getMethods();
                    // methods.invoke(obj, args);
                    method.invoke(obj, args);
                    System.out.println("动态代理完成啦...");
                    return null;
                }
            };
            T proxyInstance = (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, invocationHandler);
            return proxyInstance;
        }
    }
    
    // 动态代理
    DynamicProxy<Action> dynamicProxy = new DynamicProxy();
    Action proxy = dynamicProxy.getProxy(Action.class, new Host());
    proxy.display();
    

    动态代理稍微深入一些:

    先不和Spring的Aop写的那么复杂,我先简单实现一下,其中NxjBefore就是前置方法,NxjAfter就是后置方法
    
    // 定义这两个注解
    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @interface NxjBefore {
    }
    
    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @interface NxjAfter {
    }
    
    // 接口
    interface IMyReflect {
        void display();
    }
    
    // 被代理类
    class MyReflect implements IMyReflect{
        @Override
        public void display() {
            System.out.println("执行方法");
        }
    }
    
    class MyReflectTest{
        /**
         * 为了测试,包含注解有NxjBefore;NxjAfter这两个先测试
         */
        @NxjBefore
        public void test01() {
            System.out.println("嗯哼,before啦");
        }
    
        @NxjAfter
        public void test02() {
            System.out.println("嗯哼,after啦");
        }
    }
    
    // 自己写一下动态代理(大框和上方写的一样)
    static class DynamicProxy<T> {
        public T getProxy(Class<?> clazz, T obj, Object aop, Object... args){
            InvocationHandler invocationHandler = new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("动态代理之前干的...事情");
                    // 排好顺序
                    Map<Class<?>, List<Method>> chain = chain(aop.getClass().getMethods());
                    // 顺序调用(可以仿照Spring中AOP递归调用,这里我先简单测试一下)
                    List<Method> listBefore = chain.get(NxjBefore.class);
                    for (Method method1 : listBefore) {
                        method1.invoke(aop);
                    }
                    method.invoke(obj,args);
                    List<Method> listAfter = chain.get(NxjAfter.class);
                    for (Method method1 : listAfter) {
                        method1.invoke(aop);
                    }
                    System.out.println("动态代理完成啦...");
                    return null;
                }
            };
            T proxyInstance = (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, invocationHandler);
            return proxyInstance;
        }
    }
    
    private static Map<Class<?>, List<Method>> chain(Method[] methods) {
        Map<Class<?>, List<Method>> res = new HashMap<>();
        List<Method> beforeList = new ArrayList<>();
        List<Method> afterList = new ArrayList<>();
        for (Method method : methods) {
            Annotation[] annotations = method.getDeclaredAnnotations();
            for (Annotation annotation : annotations) {
                Class<? extends Annotation> aClass = annotation.annotationType();
                if (aClass.equals(NxjBefore.class)) {
                    beforeList.add(method);
                    break;
                } else if (aClass.equals(NxjAfter.class)) {
                    afterList.add(method);
                }
            }
        }
        res.put(NxjBefore.class, beforeList);
        res.put(NxjAfter.class, afterList);
        return res;
    }
    
    public static void main(String[] args) {
        DynamicProxy<IMyReflect> dynamicProxy = new DynamicProxy();
        IMyReflect proxy = dynamicProxy.getProxy(IMyReflect.class, new MyReflect(), new MyReflectTest());
        proxy.display();
    }
    
    # 结果
    动态代理之前干的...事情
    嗯哼,before啦
    执行方法
    嗯哼,after啦
    动态代理完成啦...
    

    当然Spring中Aop中应用动态代理,方法执行是递归执行,大致过程为先通过方法获取链chain[此时代理对象内部方法就是按照注解标注的方式排序好的],然后递归执行方法,由后往前,当是最后一个方法是调用invoke,然后依次弹栈执行。

    一篇很好的文章,值的看看:https://www.cnblogs.com/gonjan-blog/p/6685611.html

  • 相关阅读:
    焦点的相关属性和方法
    laravel 环境配置
    fetch body里数据为ReadableStream 解决办法
    解决NodeJS+Express模块的跨域访问控制问题:Access-Control-Allow-Origin
    mongo启动
    react-native android 打包发布
    delphi 还原窗口
    窗口还原
    款式修改窗口,开发调整过窗口格局保存功能,关了窗口重新打开还是按关闭前的格局.
    希尔排序算法
  • 原文地址:https://www.cnblogs.com/ningxinjie/p/14356058.html
Copyright © 2011-2022 走看看