Java 反射6-动态代理模式

动态代理

  动态代理模式的核心特点:一个代理类可以代理所有需要被代理的接口的子类对象,如下所示:

动态地理示意图

  N个接口, N+1个类, 其中 N 个真是业务类,1个代理类(在运行时动态获取当前要代理的接口)。

  所以要使用动态代理,那么其代理类类特点必须一致(代理流程一致)。

在Java动态代理中,有两个重要的接口和类,首先我们来熟悉一下。
- InvocationHandler接口

  每一个动态代理类都必须要实现InvocationHandler这个接口,这个接口中只存在一个抽象方法。并且为每个代理类的实例对象都关联一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转为由InvocationHandler这个接口的 invoke 方法来进行调用。

/* @proxy:   指代我们所代理的那个真实对象
 * @method:  指代的是我们所要调用真实对象的某个方法的Method对象
 * @args:    指代的是调用真实对象某个方法时接受的参数
 *
 * @return     方法的返回值
 * @throws     Throwable 可能产生的异常
 */
public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
  • Proxy类

  Proxy这个类的作用就是用来动态创建一个代理对象的类,我们一般使用该类中的:

/*
 * @loader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
 * @interfaces: 一个Interface对象的数组,表示的是要给需要代理的对象提供一组什么接口
 * 如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
 * @h: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候
 * 会关联到哪一个InvocationHandler对象上
 */
public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

  接下来,我们来实战演练一下。

// 业务接口
interface ISubject {
    public void eat();
}

// 真实业务类
class RealSubject implements ISubject {
    @Override
    public void eat() {
        System.out.println("吃饭");
    }
}

// 动态代理类必须实现 InvocationHandler 接口
class ProxySubject implements InvocationHandler {

    // 指向绑定的接口对象,因为是动态代理,所以接口对象的引用得用Object类
    private Object target;

    // 传入要绑定的真实业务类  
    public Object Binder(Object target) {
        this.target = target;
        // 返回该真实业务类的代理业务类
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                                    target.getClass().getInterfaces(), this);
    }

    // 辅助业务1
    public void prepareEat() {
        System.out.println("洗手");
    }

    // 辅助业务2
    public void afterEat() {
        System.out.println("洗碗");
    }

    // 这是 InvocationHandler接口唯一的方法,JDK规定要想实现动态代理,必须覆写该方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        this.prepareEat();
        Object ret = method.invoke(this.target, args);
        this.afterEat();
        return ret;
    }

}


public class Test {
    public static void main(String[] args) throws Exception {
        // Binder传入真实业务类返回该类对应的代理业务类
        ISubject subject = (ISubject) new ProxySubject().Binder(new RealSubject());
        subject.eat();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值