java动态代理实现步骤解析



当我们使用代理方法的时候,我们希望实现以下目的:

代理角色,内部含有对真实对象RealSubject的引用,从而可以操作真实对象。代理对象提供与真实对象相同的接口,以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。

我们常常这样的情况,有n各主题类,但是代理类中的“前处理、后处理”都是一样的,仅调用主题不同。也就是说,多个主题类对应一个代理类,共享“前处理,后处理”功能,动态调用所需主题,大大减小了程序规模,这就是动态代理模式的特点。比较熟悉的就是我们常说的AOP编程。


动态代理模式的含义可以分为三层来理解:
1、给某一个对象提供一个代理,并由代理对象控制对原对象的引用。代理对象和被代理对象具有同样的接口,能够像操作原对象一样操作代理对象。(代理)
2、能够使用同一套代码代理多个主题类的方法,处理前处理和后处理问题,增加程序的复用性。(复用)
3、由程序动态实现上述目的。(自动化)

下面 ,我们举个例子一步步实现上面三个步骤:
第一步 实现静态代理
//1.抽象接口
public interface Target {
    void doSomething();
}
//2.真实类
public class TargetReal implements Target {
    public void doSomething() {
        System.out.println("Admin do something.");
    }
}
//3.代理
public class TargetProxy implements Target{
    private Target target;
   
    public TargetProxy(Admin target) {
        super();
        this.target = target;
    }
 
    public void doSomething() {
        System.out.println("操作一");
        target.doSomething();
        System.out.println("操作二");
    }
}
//4.测试代码
        Target target = new TargetReal();
        Target proxy = new TargetProxy(target);
        proxy.doSomething();
以上,我们实现了对Target类中doSomething的静态代理,我们可以在doSomething的前后添加任意逻辑。
第二步:实现复用
下面,假设我们要对许多类进行代理,但为他们添加的逻辑都是一样的,那么我们为他们写下代理类的时候,这部分代码可以进行复用。其中,唯一变化的是
target.doSomething()这个方法。
这里,我们通过对这个方法进行代理,实现对多个这样方法的复用。
我们队TargetProxy进行改造
public class TargetProxy implements Target{
    private Target target;
    private proxyHandler h;
    public TargetProxy(Admin target) {
        super();
        this.target = target;
        h = new CacheHandler();
    }
    public void doSomething() {
            Class[] argTypes = new Class[] {};
            Method method = this.getClass().getMethod("doSomething", argTypes);//获取我们需要代理的方法
            Object[] args = new Object[] {};//传入该方法的参数,本方法没有参数则为空
            return h.invoke(target, method, args);
    }
}

public class proxyHandler {
    public Object invoke(Object instance,Method method,Object[] args){
        System.out.println("操作一");
        method.invoke(instance, args);
        System.out.println("操作二");
    };
}
如此一来,需要进行操作一和操作二的方法,均可以通过使用CacheHandler这个类来协助代理,实现了代码的复用。
第三步:通过java的反射,在运行时生成代理类
上面两个步骤,其实我们已经能够比较全面的体验到代理给我们带来的好处了。但目前为止,所有的代理类和以及里面的方法全部需要我们手动完成,虽然实现了一部分代码的复用,但是工作量仍然非常大,所以,java的动态代理实现了这个步骤的自动化,其中核心就是反射。
java通过动态代理实现了类似上一步中的两个类,其中代理类是自动生成的。
在java动态代理中,有两个关键的类
1、我们需要一个Handler,用于写下我们通用的代理方法,这个Handler继承自InvocationHandler。也就是我们上一步骤中proxyHandler的角色。
2、Proxy类,它有个静态方法用于生成我们的代理类,这个代理类继承自Proxy类。也就是我们上一步中的TargetProxy。
这个生成代理类的静态方法为
public static Object newProxyInstance(ClassLoader loader, Class<?>[]interfaces,InvocationHandler h) throws IllegalArgumentException;
从他的参数中我们可以看到三个必要条件:
1、被代理的类的ClassLoader
2、被代理类的所有接口
3、写下代理方法的InvocationHandler对象
其中:
1、ClassLoader用于代理类的加载(将原始字节转换成 Class 对象,以将该文件转换成类)
2、接口决定了代理类的所有方法
3、InvocationHandler决定了代理类的代理方法中调用的方法来源。也就是上一步TragetProxy中private proxyHandler h 这个属性。
newProxyInstance的大致步骤如下:
1、根据所有接口中的方法,生成具有该方法的二进制文件。
2、使用ClassLoader将二进制文件变成类。
通过以上两步我们已经得到了一个和被代理类接口相同,同时继承自Proxy的类。此时和InvocationHandler还没有关系。
3、生成一个代理类的实例,构造时使用InvocationHandler作为入参,使其获得属性。(由于继承自Proxy,所以具有该属性)
由此得到的代理类,可以完成被代理类的所有接口。其执行的方法均为handelr类中的invoke,其中method.invoke方法实现了对被代理方法的完整引用。

具体的实现方法可以看源码,我在理解代理时看的这篇文章,感谢作者,顺便推荐:
http://www.cnblogs.com/flyoung2008/archive/2013/08/11/3251148.html

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值