JDK|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。
模板配置使用
【JDK|JDK 动态代理 应用】这里展示一种之前说的真实用法。就是把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动态代理,提供了运行时创建代理的能力。根据代理特性,可以扩展其用法,不仅仅是代理的任务上。因为代理的本身是生成对象。

    推荐阅读