动态代理

1、概述
    在Java中,动态代理是指代理类的生成发生在程序运行时期,根据被代理类动态生成代理类的字节码文件(class文件),并且装载到运行环境中,像其他的类一样使用,该字节码文件的生存期随着运行环境的关闭而消失。JDK1.3以及之上的版本提供了动态代理的机制,它和反射机制结合在一起。

    JDK提供的接口和类
    InvocationHandler接口:
    public interface InvocationHandler {
        Object invoke(Object proxy, Method method, Object[]args) throws Throwable;
    }


它定义了唯一的方法invoke,该方法的参数为代理对象proxy,截获的方法对象method,和方法调用的参数,返回方法执行的结果。开发者需要实现该接口,在invoke方法中添加对截获的方法的代理操作,并调用被代理对象的方法。
Proxy类
    该类是生成代理类的帮助类,主要方法如下:
    public Static Class getProxyClass (ClassLoader loader, Class[] interfaces):根据指定的类加载器和接口获得一个代理类,其中,loader是类加载器,interfaces是被代理类所拥有的接口。
    public Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):根据指定的类加载器、接口以及截获器,返回代理类的一个实例对象。其中:
    ClassLoader loader   ----指定被代理对象的类加载器
    Class[] Interfaces   ----指定被代理对象所以事项的接口
    InvocationHandler h  ----指定需要调用的InvocationHandler对象

2、动态代理的实现
    场景如下:定义一个人类接口UserManager,UserManagerImpl是该接口的一个实现类,用于实现用户的增、删、改、查功能。现在,需要在执行这些功能之前验证安全性。
接口和实现类:
UserManager类:
    public interface UserManager {
        public void add(String username, String password);
        public void delete(String id);
        public String loadById(String id);
        public void update(String username, String password);
    }

    UserManagerImpl类:
    public class UserManagerImpl implements UserManager {
        public void add(String username, String password) {
            System.out.println("==========add()==========");
        }
        public void delete(String id) {
            System.out.println("==========delete()==========");
        }
        public String loadById(String id) {
            System.out.println("==========load()==========");
        return null;
        }
        public void update(String username, String password) {
            System.out.println("==========update()==========");
        }
    }

基于JDK的动态代理的实现
截获器SecurityHandler类:
    public class SecurityHandler implements InvocationHandler {
        private Object targetObject;// 被拦截的类
        public Object newProxy(Object targetObject) {
            this.targetObject = targetObject;
            return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);// 利用Proxy类取得代理对象
        }
        // 调用目标对象的方法是会执行下面这个方法
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            checkSecurity();
            Object ret = null;
            try {
                ret = method.invoke(this.targetObject, args);
            } catch (Exception e) {
                e.printStackTrace();
            throw e;
            }
            return ret;
        }
        private void checkSecurity() {
            System.out.println("==========checkSecurity()==========");
        }
    }

    其中invoke()方法就是Proxy动态代理类所代理的接口类的抽象方法的真实实现:
    Object proxy     -----代理类对象
    Method method    -----被代理对象的方法(这里不是接口的抽象方法了,是具体的实现类中的方法)
    Object[] args    -----该方法的参数数组
    说明:这里可以把上面的类抽象分成两个类处理,即SecurityHandler和SecurityProxyCreator类:
    public class SecurityHandler implements InvocationHandler {
        private Object targetObject;// 被拦截的类
        public void setTargetObject(Object targetObject) {
           this.targetObject = targetObject;
        }
        // 调用目标对象的方法是会执行下面这个方法
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            checkSecurity();
            Object ret = null;
            try {
                ret = method.invoke(this.targetObject, args);
            } catch (Exception e) {
                e.printStackTrace();
            throw e;
            }
            return ret;
        }
        private void checkSecurity() {
            System.out.println("==========checkSecurity()==========");
        }
    }
    public class SecurityProxyCreator {
        public Object create(Class<?>[] interfaces, InvocationHandler h) {  
            return Proxy.newProxyInstance(this.getClass().getClassLoader(), interfaces, h);
        }
    }

    Client测试类:
    public class Client {
        public static void main(String[] args) {
            SecurityHandler handler = new SecurityHandler();
            UserManager userManager = (UserManager) handler.newProxy(new UserManagerImpl());// 生成代理类
            userManager.add("", "");
        }
    }

    测试结果如下:
    ==========checkSecurity()==========
    ==========add()==========
    3 分析总结
    分析JDK提供的帮助类Proxy,可以发现,它只支持实现接口方式的代理,不支持继承超类方式的代理,这就意味着,被代理的类必须要有接口,并且需要拦截的方法必须都在接口中进行声明。在本例中,通过截获帮助类Proxy生成的代理类的字节码文件,反编译之后,发现,其类的声明如下:
    public final class proxy0 extends Proxy implements UserManager
    其中,proxy0就是动态生成的代理类的名字,在该类的方法中,都会将调用委托到拦截器的invoker方法。
    JDK中具体的动态代理类是怎么产生的呢?
    1、产生代理类$Proxy0类
    执行了Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
    产生$Proxy0类,它继承Proxy对象,并根据第二个参数,实现了被代理类的所有接口,自然就可以生成接口要实现的所有方法了(这时候会重写hashcode,toString和equals三个方法),但是还没有具体的实现体;
    2、将代理类$Proxy0类加载到JVM中
    根据Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)它的第一个参数----就是被代理类的类加载器,把当前的代理类加载到JVM中
    3、创建代理类$Proxy0类的对象
    调用的$Proxy0类的$Proxy0(InvocationHandler)构造函数,生成$Proxy0类的对象
    参数就是Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)它的第三个参数
    这个参数就是实现的InvocationHandler对象,InvocationHandler对象中组合加入了代理类代理的接口类的实现类;所以,$Proxy0对象调用所有要实现的接口的方法,都会调用InvocationHandler对象的invoke()方法实现;
    4、生成代理类的class byte
    动态代理生成的都是二进制class字节码
    备注:JDK提供的动态代理仅支持接口方式的代理,那么如果被代理的类没有实现任何接口,则可基于CGLib的动态代理,CGLib同时也支持继承超类的方式的代理。

你可能感兴趣的:(动态代理)