关闭

Java动态代理

标签: Java动态代理
91人阅读 评论(0) 收藏 举报
分类:

代理

有时候我们不希望直接访问对象A,而是希望通过访问中介对象B,由B来访问A,这种方式就是我们所说的代理。这里的类A即为委托类(被代理类),B为代理类。那么使用代理的好处是什么呢?

  1. 隐藏委托类的实现
  2. 实现解耦,在不改变委托类的情况下,对代理类进行修改,实现额外的处理。
    代理分为静态代理和动态代理。

静态代理

所谓静态代理就是程序运行之前代码中存在代理类,静态代理中代理类和委托类也常常继承同一父类或实现同一接口。

public interface Behaviour {
    void method();
}
//委托类
public class Principal implements Behaviour{
    public void method() {
        System.out.println("principle.method");
    }
}
//代理类
public class Agent implements Behaviour {
    private Principal principal;
    public Agent(Principal principal){
       this.principal = principal;
    }
    public void method() {
        principal.method();
    }
}

代理类持有委托类对象的引用,通过调用委托类对象的方法实现代理。使使用者和委托类之间解耦,但是缺点是我们要提前写好代理类。

动态代理

程序运行过程中创建代理类,这种方式叫动态代理。代码中不需要专门去写一个代理类。

动态代理的实现方式
  1. 新建行为接口和委托类
  2. 新建一个类实现InvocationHandler接口,这是负责连接代理类和委托类的中间类必须实现的接口
  3. 通过Proxy类产生代理类对象。
    先来新建行为接口和委托类
public interface Behaviour {
    void method();
}
//委托类
public class Principal implements Behaviour{
    public void method() {
        System.out.println("principle.method");
    }
}

再来写一个类实现InvocationHandler接口,

public class MyInvocation implements InvocationHandler {
    private Object principal;

    public MyInvocation(Object principal) {
        this.principal = principal;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = method.invoke(principal,args);
        return result;
    }
}

这里解释一下InvocationHandler接口里的public Object invoke(Object proxy, Method method, Object[] args) throws Throwable方法各个参数代表的意思,proxy是后面要生成的代理类对象,method表示代理对象被调用的函数。args表示代理对象被调用的函数的参数。
从上面代码我们看到,中介类持有委托类对象引用,在invoke方法中调用了委托类对象的相应方法。实际上,中介类与委托类构成了静态代理关系,在这个关系中,中介类是代理类,委托类就是委托类;代理类与中介类也构成一个静态代理关系,在这个关系中,中介类是委托类,代理类是代理类。也就是说,动态代理关系由两组静态代理关系组成,这就是动态代理的原理。

通过Proxy类产生代理类对象
public class Example {
    public static void main(String args[]) {
        Principal principal = new Principal();//构造一个委托类对象
        MyInvocation myInvocation = new MyInvocation(principal);//构造中介类,并把委托类对象传入
        Behaviour behaviour = (Behaviour) Proxy.newProxyInstance(Behaviour.class.getClassLoader(),
                new Class[]{Behaviour.class},myInvocation);//动态生成代理类对象
        behaviour.method();
    }

}

这里通过Proxy.newProxyInstance(Behaviour.class.getClassLoader(),
new Class[]{Behaviour.class},myInvocation);//动态生成代理类对象
,这个方法的三个参数,第一个参数是定义代理类的Classloader,第二个参数是委托类实现的接口列表,第三个参数是我们实现的invocaition接口实例。
当我们调用代理类的方法时,behaviour.method();,实际会调用MyInvocation里的public Object invoke(Object proxy, Method method, Object[] args)方法,而这个方法里又会调用委托类的相应方法,所以额外的处理逻辑一般都在这个方法里实现。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:9533次
    • 积分:616
    • 等级:
    • 排名:千里之外
    • 原创:54篇
    • 转载:0篇
    • 译文:0篇
    • 评论:4条
    最新评论