动态代理

2019-03-10  本文已影响0人  胖达_4b7e

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类 里面静态方法

定义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代理的是类,创建的对象只有一个。

上一篇 下一篇

猜你喜欢

热点阅读