美文网首页
动态代理

动态代理

作者: 胖达_4b7e | 来源:发表于2019-03-10 17:32 被阅读0次

    https://mp.weixin.qq.com/s/RUremX34F1ETpwARLO76mg

    静态代理

    public class SimpleStaticProxyDemo {
    
    // 都实现这个接口
        static interface IService {
            public void sayHello();
        }
    
    // 被代理的类
        static class RealService implements IService {
    
            @Override
            public void sayHello() {
                System.out.println("hello");
            }
        }
    
    // 代理
        static class TraceProxy implements IService {
            private IService realService;
    
            public TraceProxy(IService realService) {
                this.realService = realService;
            }
    
            @Override
            public void sayHello() {
                System.out.println("entering sayHello");
                // 调用实际干活类
                this.realService.sayHello();
                System.out.println("leaving sayHello");
            }
        }
    
        public static void main(String[] args) {
    
            IService realService = new RealService();
    
    // 实际干活的类 传入代理类
            IService proxyService = new TraceProxy(realService);
    
    // 客户自己使用的是代理类 
            proxyService.sayHello();
        }
    }
    

    但是如果要AOP, 很多类需要类似的功能, 如果他们实现的不是IService , 就不能用这个代理类了,
    对于日志这种通用的功能, 犯不着每个接口都给它写个代理类

    Java SDK动态代理

    java.lang.reflect.Proxy类 里面静态方法
    • loader 表示类加载器

    • interfaces 表示代理类要实现的接口列表 , 想要返回的代理类是什么类型就往里加接口.class

    • h 类型为InvocationHandler,它是一个接口,也定义在java.lang.reflect包中, 就是在里面写对目标类的改造

    • 返回值: 返回值类型为Object,可以强制转换为interfaces数组中的一个接口类型

    定义h: 同一的附加功能是日志

        static class SimpleInvocationHandler implements InvocationHandler {
            private Object realObj;
    
            public SimpleInvocationHandler(Object realObj) {
                this.realObj = realObj;
            }
    
             /**
             * 
             * @param proxy 代理对象本身
             * @param method 调用的方法
             * @param args 传参
             * @return
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
                System.out.println("entering " + method.getName());
                // Object result = method.invoke(proxy, args); 如果改成这样会死循环
                Object result = method.invoke(realObj, args);
                System.out.println("leaving " + method.getName());
                return result;
            }
        }
    

    使用:

       public static void main(String[] args) {
    
            IService realService = new RealService();
    
            ClassLoader classLoader = IService.class.getClassLoader();
            Class<?>[] interfaces = {IService.class};
            SimpleInvocationHandler h = new SimpleInvocationHandler(realService);
    
            IService proxyService = (IService) Proxy.newProxyInstance(classLoader, interfaces, h);
            proxyService.sayHello();
        }
    

    其中
    IService proxyService = (IService) Proxy.newProxyInstance(classLoader, interfaces, h);
    可以替换为:

    Class<?> proxyCls = Proxy.getProxyClass(classLoader, interfaces);
    Constructor<?> ctor = proxyCls.getConstructor(new Class<?>[]{InvocationHandler.class });
    IService proxyService = (IService) ctor.newInstance(h);
    

    Proxy.getProxyClass(类加载器,接口数组)
    它会动态生成一个类,类名以$Proxy开头,后跟一个数字
    这个动态生成的类 与被代理的对象没有关系,与InvocationHandler h的具体实现也没有关系,只与接口数组有关

    public class $Proxy0 extends Proxy 
    implements SimpleJDKDynamicProxyDemo.IService{//实现了接口IService
        private static Method m1;
        private static Method m3;
        private static Method m2;
        private static Method m0;
    
        // 注意这个构造方法 传入h 其他方法都会交给h
        public $Proxy0(InvocationHandler h) {
            super(h);
        }
    
        @Override
        public final boolean equals(Object paramObject) {
            return ((Boolean) this.h.invoke(this, m1,
                    new Object[] { paramObject })).booleanValue();
        }
    
        @Override
        public final void sayHello() {
            //  交给h了
            this.h.invoke(this, m3, null);
        }
    
        @Override
        public final String toString() {
            return (String) this.h.invoke(this, m2, null);
        }
    
        @Override
        public final int hashCode() {
            return ((Integer) this.h.invoke(this, m0, null)).intValue();
        }
    
        static {
            m1 = Class.forName("java.lang.Object").getMethod("equals",
                    new Class[] { Class.forName("java.lang.Object") });
            m3 = Class.forName("laoma.demo.proxy.SimpleJDKDynamicProxyDemo$IService")
                    .getMethod("sayHello",new Class[0]);
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
        }
    }
    

    动态代理, 把实现的接口 和 handle 和被代理类 分离, 不同的接口可以用同一个handle,
    但是, 必须是有有接口的类 才能被动态代理,返回的代理对象也只能转换到某个接口类型,如果一个类没有接口,或者希望代理非接口中定义的方法,那就没有办法了。

    cglib动态代理

    基于ASM
    第三方的类库cglib(https://github.com/cglib/cglib)可以做到这一点,Spring,Hibernate等都使用该类库。

    cglib的实现机制与Java SDK不同,通过继承实现的,也是动态创建了一个类,父类是被代理的类,代理类重写了父类的所有public非final方法,改为调用Callback中的相关方法

    被代理的类: 没有接口

    class RealService {
            public void sayHello() {
                System.out.println("hello");
            }
        }
    

    要加的功能:

    class SimpleInterceptor implements MethodInterceptor {
    
            /**
             *
             * @param object 代理对象
             * @param method
             * @param args 传参
             * @param proxy
             * @return
             * @throws Throwable
             */
            @Override
            public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable {
    
                System.out.println("entering " + method.getName());
    
                Object result = proxy.invokeSuper(object, args);
    
                System.out.println("leaving " + method.getName());
                return result;
            }
        }
    

    使用:

        /**
         *
         * @param cls 被代理的类
         * @param <T> 被代理类的类型
         * @return 代理
         */
        @SuppressWarnings("unchecked")
        private static <T> T getProxy(Class<T> cls) {
    
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(cls);//设置被代理的类
    
            // 设置处理类
            enhancer.setCallback(new SimpleInterceptor());
            return (T) enhancer.create();
        }
    
        public static void main(String[] args) {
            // 直接对类代理  不用创建原类的实例
            RealService proxyService = getProxy(RealService.class);
            proxyService.sayHello();
        }
    

    Java SDK代理的是对象,需要先有一个实际对象,
    cglib代理的是类,创建的对象只有一个。

    相关文章

      网友评论

          本文标题:动态代理

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