Java 动态代理

动态代理简介:

动态代理是一种强大的功能,它可以在运行时动态创建一个类,实现一个或者多个接口,可以在不修改原来的类的基础上动态的添加方法,修改行为。

静态代理:

代理是java 设计模式中的一种,基础概念和日常生活中的概念类似。代理背后一般至少有一个实际对象,代理的外部功能和实际对象一般是一样的,用户和代理打交道,不直接接触实际对象,虽然外部公共和实际对象一样,但代理有它存在的价值。比如:

(1) 节省成本比较高的实际对象的创建开销,按需延迟加载,创建代理时并不真正创建实际对象,而只是保存实际对象的地址,在需要时再加载或创建。

(2) 执行权限检查,代理检查权限后,在调用实际对象。

(3) 屏蔽网络差异和复杂性,代理在本地,而实际对象在其它服务器上,调用本地代理时,请求其它服务器。

静态代理示例:

package Proxy;

/**
 * 静态代理
 */
public class StaticProxy {

    interface Iservice {
        void sayHello();
    }

    static class RealService implements  Iservice {

        @Override
        public void sayHello() {
            System.out.println("I'm RealService!");
        }
    }

    static class ProxyService implements Iservice {
        private RealService realService;

        public ProxyService(RealService realService) {
            this.realService = realService;
        }

        @Override
        public void sayHello() {
            realService.sayHello();
            System.out.println("I'm ProxyService!");
        }
    }

    public static void main(String[] args) {
        RealService realService = new RealService();
        ProxyService proxyService = new ProxyService(realService);
        proxyService.sayHello();
    }
}

java sdk动态代理:

在静态代理中,代理类是直接定义在代码中的,在动态代理中,代理类是动态生成的。

示例:

package Proxy;

import java.lang.reflect.*;

/**
 * 动态代理demo
 */
public class SimpleJDKDynamicsDemo {

    interface  Iservice {
        public void sayHello();
    }

    static class RealService implements Iservice {

        @Override
        public void sayHello() {
            System.out.println("I'm RealService say Hello!");
        }
    }

    static class SimpleInvocationHandler implements InvocationHandler {

        //被代理对象
        private Object object;

        //给被代理对象赋值
        public SimpleInvocationHandler(Object object) {
            this.object = object;
        }

        /**
         *
         * @param proxy  代表代理对象本身,不是被代理的对象,这个参数一般用处不大
         * @param method 表示正在调用的方法
         * @param args    表示方法的参数
         * @return
         * @throws Throwable
         *   不能将传进来的proxy作为参数使用到menthod 的invoke()方法中做参数,因为proxy表示当前代理对象,用
         *   proxy 当参数又会直接调用到SimpleInvocationHandler 的invoke 方法
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("调用的方法是: "+method.getName());
            Object result = method.invoke(object,args);
            System.out.println("结束时调用的方法:"+method.getName());
            return result;
        }
    }

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Iservice realService1 = new RealService();
        //newProxyInstance(ClassLoader loader,Class<?> [] interfaces,InvocationHandler h)
        //.loader 表示类加载器
        //.interfaces 表示代理类要实现的接口列表,是一个数组,元素的类型只能是接口,不能是普通的类
        //.h的类型为InvocationHandler,它是一个接口,也定义在java.lang.reflect包中,它之定义了一个方法invoke,对
        //代理接口的所有方法的调用都会转给该方法
        //newProxyInstance()的返回值是Object,可以强制转换为intefaces 里的某个接口类型,但它不能强制转为
        //某个类类型,即使是它的实际代理的对象类型,因为子类可以装一下父类还可以转换回去,
        // 但是父类却不能装为子类,并不知道子类的那些东西
        Iservice proxyIservice = (Iservice) Proxy.newProxyInstance(
                Iservice.class.getClassLoader(),
                new Class[]{Iservice.class},
                new SimpleInvocationHandler(realService1));
        proxyIservice.sayHello();

        //动态代理的基本原理
        Iservice realService = new RealService();
        //创建代理类定义,定义会被缓存
        Class<?> proxyCls = Proxy.getProxyClass(Iservice.class.getClassLoader(),Iservice.class);
        //获取代理类的构造方法,构造方法有一个InvocationHandler对象
        Constructor<?> ctor = proxyCls.getConstructor(InvocationHandler.class);
        //创建InvocationHandler对象,创建代理类对象
        InvocationHandler handler = new SimpleInvocationHandler(realService);
        //$Proxy0 是代理类的 类定义
        Iservice proxyService = (Iservice) ctor.newInstance(handler);
        proxyService.sayHello();
    }
}

动态代理的基本原理分为三步:
(1)通过Proxy.getProxyClass() 创建代理类定义,类定义会被缓存。

(2)通过反射,获取到代理类的构造方法,构造方法 有一个InvocationHander类型的参数。

(3) 创建自定义Hander 继承InvocationHander 接口,实现自定义的代理逻辑,最后创建代理类。

生成的代理类如下:



package Proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * java SDK动态生成的代理类示例
 *$Proxy0 的父类是proxy,proxy类定义了一个InvocationHandler类型的参数,
 *$Proxy0 的构造方式是为了保存InvocationHandler,
 * $Proxy0 同样也实现了Iservice接口,当$Proxy0 调用sayHello方法时,会转发给InvocationHandler的实现类取去处理
 */


final class $Proxy0 extends Proxy implements SimpleJDKDynamicsDemo.Iservice {

    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static  Method m0;

    public $Proxy0(InvocationHandler h) {
        super(h);
    }

    public final void sayHello() {
      this.h.invoke(this,m3,null);
    }

    public final int hashCode() {
        return ((Integer) this.h.invoke(this,m0,null)).intValue();
    }

    public final boolean equals(Object obj) {
        return ((Boolean) this.h.invoke(this,m1,new Object[]{obj})).booleanValue();
    }

    public final String toString() {
        return (String) this.h.invoke(this,m2,null);
    }

    static{
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals",
                    new Class[]{Class.forName("java.lang.Object")});
            m3 = Class.forName("Proxy.SimpleJDKDynamicsDemo$Iservice")
                    .getMethod("sayHello",new Class[0]);
            m2 =Class.forName("java.lang.Object").getMethod("toString");
            m0 =Class.forName("java.lang.Object").getMethod("hashCode");

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}


通用的动态代理类示例:

package Proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 通用动态代理实例
 *
 * 共享同一个代理逻辑SimpleInvocationHandler,去获取代理对象执行方法
 */
public class CommonProxyDemo {

    interface IserviceA {
        void sayHello();
    }

    interface IServiceB {
        void fly();
    }

    static class ServiceAImpl implements IserviceA {

        @Override
        public void sayHello() {
            System.out.println("IserviceA say Hello!");
        }
    }

    static class ServiceBImpl implements IServiceB {

        @Override
        public void fly() {
            System.out.println("IserviceB say fly!");
        }
    }

    static class SimpleInvocationHandler implements InvocationHandler {

        private Object object;

        public SimpleInvocationHandler(Object object) {
            this.object = object;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("entering" + object.getClass().getSimpleName() + "::"+ method.getName());
            Object result = method.invoke(object,args);
            System.out.println("leaving" + object.getClass().getSimpleName() + "::" + method.getName());
            return result;
        }
    }

    public static <T> T getProxy(Class<?> cls,T obj){
        return (T) Proxy.newProxyInstance(cls.getClassLoader(),
                new Class[]{cls},new SimpleInvocationHandler(obj));
    }

    public static void main(String[] args) {
        IserviceA a = new ServiceAImpl();
        IserviceA aProxy = getProxy(IserviceA.class,a);
        aProxy.sayHello();
        IServiceB b = new ServiceBImpl();
        IServiceB bProxy = getProxy(IServiceB.class,b);
        bProxy.fly();

    }
}

CGLIB 动态代理:

Java sdk 动态代理的局限在于,它只能代理为接口创建对象。返回的代理对象也只能是转换到某个接口类型。如果一个类没有接口,或者希望代理非接口中定义的方法,那就没办法了。但有一个地方法类库cglib,可以做到这一点.它通过继承这个类,重写这个类的方法。

示例:

package Proxy;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 *java sdk 动态代理的局限是只能为接口创建代理,返回的代理对象也只能转换为接口类型
 * 要实现不是接口的代理需要用到第三方的类库,cglib,它是通过继承实现的,它也是动态创建一个类,
 * 但这个类的父类是被代理的类,代理类重写父类的所有public非final方法,改为调用Callback中的相关方法
 */
public class SimpleCGLBDynamicsDemo {

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

    static class SimpleInterceptor implements MethodInterceptor {

        @Override
        public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            System.out.println("entering" + method.getName());
            Object result = methodProxy.invokeSuper(o,args);
            System.out.println("leaving" + method.getName());
            return  result;
        }
    }

    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) {
         RealSerice realSericeProxy = getProxy(RealSerice.class);
         realSericeProxy.sayHello();
    }
}

总结:

动态代理广泛的应用于各种系统程序,框架/库。用于为应用程序提供易用的支持,实现Aop,以及其它灵活的通用功能。理解了动态代理,我们就能更好的利用这些系统程序、框架、库,在需要的时候也可以自己创建动态代理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值