動態(tài)代理的思想來源于 代理模式
本片文章不講述設(shè)計模式,需要學(xué)習(xí)設(shè)計模型知識請自行查閱資料.
被代理類
JDK動態(tài)代理要求被代理類只能是接口或者實現(xiàn)某接口的類。
此處定義被代理接口
public interface BeProxyInterface {
/**
* 聲明被代理方法
* @param msg 參數(shù)
* @return
*/
Object call(String msg);
}
代理類
我更喜歡把代理類叫做 觸發(fā)控制類,因為代理類必須要實現(xiàn)InvocationHandler
public class Advised implements InvocationHandler {
/**
* 觸發(fā)被代理的方法
* @param proxy 代理對象
* @param method 當(dāng)前觸發(fā)的方法
* @param objects 當(dāng)前觸發(fā)方法的入?yún)? * @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] objects) throws Throwable {
System.out.println("-------觸發(fā)了方法-------");
return null;
}
}
創(chuàng)建代理對象
Object proxy = Proxy.newProxyInstance(BeProxyInterface.class.getClassLoader(), new Class[] {BeProxyInterface.class}, new Advised());
BeProxyInterface proxyObj = (BeProxyInterface)proxy;
proxyObj.call("哈哈");
以上,給BeProxyInteface接口生成了一個代理對象看峻∈亢基本就是動態(tài)代理的使用.
不過你可能會說狸页,以上示例只是打印了一行輸出路捧,沒有實際用處.
沒錯撒顿,以上示例確實沒什么實際用處丑罪,不過還是能擴(kuò)展,使其能得到真正應(yīng)用凤壁。
說到真正應(yīng)用之前吩屹,先看看網(wǎng)上其他文章可能給出的一般用法。
一般用法是觸發(fā)控制類持有被代理對象真實示例.并觸發(fā)被代理對象的方法. 如下
public class Advised implements InvocationHandler {
private BeProxyInterface beProxyInterface;
@Override
public Object invoke(Object proxy, Method method, Object[] objects) throws Throwable {
method.invoke(beProxyInterface, objects);
}
}
對應(yīng)的創(chuàng)建代理類的修改, 需要指定拧抖。
以上示例是比較常見的示例煤搜。 實際上像spring的動態(tài)代理也是這種方式,BeProxyInterface對應(yīng)的就是spring的bean(targetSource); InvocationHanderl關(guān)聯(lián)的BeProxyInterface改為關(guān)聯(lián)beanName唧席。
模板配置使用
這里展示一種之前說的真實用法擦盾。就是把InvocationHander當(dāng)成模板,被代理對象當(dāng)成可變配置使用淌哟。
可能的使用場景
消息隊列發(fā)送消息
一般的迹卢,往消息隊列方式消息,需要指定消息對象绞绒,以及接收的隊列就可以婶希。發(fā)送方法是可以公用的。即連接隊列發(fā)送消息蓬衡,連接對象可以公用喻杈,需要提供消息體和隊列名詞即可。
- 定義接口狰晚,指定消息隊列筒饰,并指定消息對象
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface RabbitMqProducer {
String exchange();
String routing();
}
public interface BeProxyInterface {
/**
* 聲明被代理方法
* @param msg 參數(shù)
* @return
*/
@RabbitMqProducer(exchange = "exchange.test.topic", routing = "routing.test")
Object call(String msg);
}
- 實現(xiàn)發(fā)送消息模板
public class Advised implements InvocationHandler {
/**
* 觸發(fā)被代理的方法
* @param proxy 代理對象
* @param method 代理對上當(dāng)前觸發(fā)的方法
* @param objects 當(dāng)前觸發(fā)方法的入?yún)? * @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] objects) throws Throwable {
System.out.println("-------觸發(fā)了方法-------");
RabbitMqProducer rabbitMqProducer = method.getAnnotation(RabbitMqProducer.class);
if (rabbitMqProducer != null) {
String exchange = rabbitMqProducer.exchange();
String routing = rabbitMqProducer.routing();
System.out.println("根據(jù)exchange:" + exchange + ", routing:" + routing + ", 發(fā)送消息 :" + objects[0]);
}
return null;
}
}
- 發(fā)送消息
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("哈哈");
}
輸出結(jié)果
-------觸發(fā)了方法-------
根據(jù)exchange:exchange.test.topic, routing:routing.test, 發(fā)送消息 :哈哈
以上,把觸發(fā)控制類當(dāng)模板來用壁晒。 要把消息發(fā)送到不通隊列瓷们,則只需要寫不同的BeProxyInterface接口即可。
總結(jié)
JDK動態(tài)代理,提供了運行時創(chuàng)建代理的能力。根據(jù)代理特性谬晕,可以擴(kuò)展其用法碘裕,不僅僅是代理的任務(wù)上。因為代理的本身是生成對象攒钳。