美文网首页
动态代理

动态代理

作者: 胖达_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代理的是类,创建的对象只有一个。

相关文章

  • 面试系列~动态代理实现与原理

    动态代理有JDK动态代理, CGLIB动态代理, SpringAOP动态代理 一,JDK动态代理  jdk动态代理...

  • 编程常用的设计模式

    动态代理和静态代理 静态代理 动态代理 静态代理与动态代理的区别 JDK中的动态代理和CGLIB 实现动态代理的方...

  • Spring的AOP原理分析

    一 动态代理 动态代理分为JDK动态代理和CGLIB动态代理 jdk动态代理 被代理类(目标类)和代理类必须实现同...

  • 设计模式之代理模式

    代理分为静态代理和动态代理。 动态代理又包括基于JDK的动态代理、基于CGlib 的动态代理、基于Aspectj实...

  • Java高级主题(五)——动态代理

    代理可以分为静态代理、动态代理,动态代理又可以分为 jvm的动态代理 和 cglib的动态代理。像spring框架...

  • 动态代理

    动态代理分为两类:1、基于接口的动态代理; (JDK动态代理 )2、基于类的动态代理;(cglib动态代理)3、J...

  • 动态代理的两种方式

    静态代理就不说了,基本用到的都是动态代理。 Java中动态代理有JDK动态代理和CGLIB动态代理。 JDK代理的...

  • Java动态代理

    通过以下几种方式介绍动态代理 动态代理涉及到的类 动态代理用法 Proxy类解析 动态代理类解析 动态代理涉及到的...

  • Spring之代理模式

    九、代理模式 目录:静态代理、动态代理AOP的底层机制就是动态代理。代理模式分为静态代理和动态代理。接触aop之前...

  • Java 代理

    静态代理 动态代理 动态代理, 日志切片使用反射获得方法 动态代理, 自定义注解(对注解的方法,使用动态代理添加切...

网友评论

      本文标题:动态代理

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