java 动态代理

来源:互联网 发布:身份证阅读器软件下载 编辑:程序博客网 时间:2024/06/18 05:03
创建Proxy对象,测试public class ProxyTest_old {     public static void main(String[] args) {        UserDao userDao = new UserDaoImpl();        LogHandler_old logHandler = new LogHandler_old(userDao);        UserDao userDaProxy = (UserDao) Proxy.newProxyInstance(userDao               .getClass().getClassLoader(), userDao.getClass()               .getInterfaces(), logHandler);        userDaProxy.delete(new User());        userDaProxy.save(new User());        userDaProxy.update(new User());     }}

解释:

  1. Proxy即动态代理类;
  2. Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用;
    它有三个参数:
    ClassLoader loader —-指定被代理对象的类加载器
    Class[] Interfaces —-指定被代理对象所以事项的接口
    InvocationHandler h —-指定需要调用的InvocationHandler对象
  3. 实现InVocationHandler接口的LogHandler_old对象
    这个对象的invoke()方法就是Proxy这个动态代理类所代理的接口类的抽象方法的真实实现;

它有三个参数:
Object proxy —–代理类对象
Method method —–被代理对象的方法(这里不是接口的抽象方法了,是具体的实现类中的方法)
Object[] args —–该方法的参数数组

JDK中具体的动态代理类是怎么产生的呢?

1.产生代理类Proxy0Proxy.newProxyInstance(ClassLoaderloader,Class[]interfaces,InvocationHandlerh)Proxy0类,它继承Proxy对象,并根据第二个参数,实现了被代理类的所有接口,自然就可以生成接口要实现的所有方法了(这时候会重写hashcode,toString和equals三个方法),但是还没有具体的实现体;

  1. 将代理类$Proxy0类加载到JVM中
    这时候是根据Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)它的第一个参数—-就是被代理类的类加载器,把当前的代理类加载到JVM中

  2. 创建代理类Proxy0Proxy0类的Proxy0InvocationHandlerProxy0类的对象
    参数就是Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)它的第三个参数

这个参数就是我们自己实现的InvocationHandler对象,我们知道InvocationHandler对象中组合加入了代理类代理的接口类的实现类;所以,$Proxy0对象调用所有要实现的接口的方法,都会调用InvocationHandler对象的invoke()方法实现;

  1. 生成代理类的class byte
    动态代理生成的都是二进制class字节码


动态代理是很多框架和技术的基础, spring 的AOP实现就是基于动态代理实现的。了解动态代理的机制对于理解AOP的底层实现是很有帮助的。

Proxy类的设计用到代理模式的设计思想,Proxy类对象实现了代理目标的所有接口,并代替目标对象进行实际的操作。但这种替 代不是一种简单的替代,这样没有任何意义,代理的目的是在目标对象方法的基础上作增强,这种增强的本质通常就是对目标对象的方法进行拦截。所 以,Proxy应该包括一个方法拦截器,来指示当拦截到方法调用时作何种处理。InvocationHandler就是拦截器的接口。

InvocationHandler接口也是在java.lang.reflec
Object invoke(Object proxy, Method method, Object[] args)
这个接口有三个参数,其中第二和第三个参数都比较好理解,一个是被拦截的方法,一个是该方法的参数列表。关键是第一个参数。按照doc文档的解析,

简单代理的例子

import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;//定义项目接口interface Subject {    public String say(String name, int age);}class RealSubject implements Subject {    @Override    public String say(String name, int age)     {        return name + "  " + age;    }}class MyInvocationHandler implements InvocationHandler {    private Object obj = null;    public Object bind(Object obj) {        this.obj = obj;        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),                         obj.getClass().getInterfaces(), this);    }    @Override    public Object invoke(Object proxy, Method method, Object[] args)            throws Throwable {        Object temp = method.invoke(this.obj, args);        return temp;    }}public class Main {        public static void main(String args[]) throws InterruptedException        {        MyInvocationHandler demo = new MyInvocationHandler();/*得到的是一个代理对象,但是该对象从外部看来,和普通的Subject的子类对象一样,可以调用方法等等,但是具体实现handle的时候,可以对invoke进行复杂的处理,从而达到限制subject的权限的作用*/       Subject sub = (Subject) demo.bind(new RealSubject());        String info = sub.say("Rollen", 20);        System.out.println(info);        }}
0 0
原创粉丝点击