JDK 动态代理 应用

动态代理的思想来源于 代理模式
本片文章不讲述设计模式,需要学习设计模型知识请自行查阅资料.

被代理类

JDK动态代理要求被代理类只能是接口或者实现某接口的类。
此处定义被代理接口

public interface BeProxyInterface {

    /**
     * 声明被代理方法
     * @param msg 参数
     * @return
     */
    Object call(String msg);
}

代理类

我更喜欢把代理类叫做 触发控制类,因为代理类必须要实现InvocationHandler

public class Advised implements InvocationHandler {

    /**
     * 触发被代理的方法
     * @param proxy         代理对象
     * @param method        当前触发的方法
     * @param objects       当前触发方法的入参
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] objects) throws Throwable {
        System.out.println("-------触发了方法-------");
        return null;
    }
}

创建代理对象

Object proxy = Proxy.newProxyInstance(BeProxyInterface.class.getClassLoader(), new Class[] {BeProxyInterface.class}, new Advised());
 BeProxyInterface proxyObj = (BeProxyInterface)proxy;
proxyObj.call("哈哈");

以上,给BeProxyInteface接口生成了一个代理对象。基本就是动态代理的使用.

不过你可能会说,以上示例只是打印了一行输出,没有实际用处.

没错,以上示例确实没什么实际用处,不过还是能扩展,使其能得到真正应用。
说到真正应用之前,先看看网上其他文章可能给出的一般用法。
一般用法是触发控制类持有被代理对象真实示例.并触发被代理对象的方法. 如下

public class Advised implements InvocationHandler {
    private BeProxyInterface beProxyInterface;
    @Override
    public Object invoke(Object proxy, Method method, Object[] objects) throws Throwable {
        method.invoke(beProxyInterface, objects);
  }
}

对应的创建代理类的修改, 需要指定。
以上示例是比较常见的示例。 实际上像spring的动态代理也是这种方式,BeProxyInterface对应的就是spring的bean(targetSource); InvocationHanderl关联的BeProxyInterface改为关联beanName。

模板配置使用

这里展示一种之前说的真实用法。就是把InvocationHander当成模板,被代理对象当成可变配置使用。

可能的使用场景

消息队列发送消息

一般的,往消息队列方式消息,需要指定消息对象,以及接收的队列就可以。发送方法是可以公用的。即连接队列发送消息,连接对象可以公用,需要提供消息体和队列名词即可。

  • 定义接口,指定消息队列,并指定消息对象
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface RabbitMqProducer {

    String exchange();

    String routing();
}
public interface BeProxyInterface {
    /**
     * 声明被代理方法
     * @param msg 参数
     * @return
     */
    @RabbitMqProducer(exchange = "exchange.test.topic", routing = "routing.test")
    Object call(String msg);
}
  • 实现发送消息模板
public class Advised implements InvocationHandler {

    /**
     * 触发被代理的方法
     * @param proxy         代理对象
     * @param method        代理对上当前触发的方法
     * @param objects       当前触发方法的入参
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] objects) throws Throwable {
        System.out.println("-------触发了方法-------");
        RabbitMqProducer rabbitMqProducer = method.getAnnotation(RabbitMqProducer.class);
        if (rabbitMqProducer != null) {
            String exchange = rabbitMqProducer.exchange();
            String routing = rabbitMqProducer.routing();
            System.out.println("根据exchange:" + exchange + ", routing:" + routing + ", 发送消息 :" + objects[0]);
        }
        return null;
    }
}
  • 发送消息
public static void main(String[] args) {
        Object proxy = Proxy.newProxyInstance(BeProxyInterface.class.getClassLoader(), new Class[] {BeProxyInterface.class}, new Advised());
        BeProxyInterface proxyObj = (BeProxyInterface)proxy;
        proxyObj.call("哈哈");
    }

输出结果

-------触发了方法-------
根据exchange:exchange.test.topic, routing:routing.test, 发送消息 :哈哈

以上,把触发控制类当模板来用。 要把消息发送到不通队列,则只需要写不同的BeProxyInterface接口即可。

总结

JDK动态代理,提供了运行时创建代理的能力。根据代理特性,可以扩展其用法,不仅仅是代理的任务上。因为代理的本身是生成对象。

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