最近上班工作不是很忙,就補了一下基礎知識,在傳智播客上找了一些免費的視頻,下載下來慢慢看,爲了讓自己很好的吸收,還是要多動手實踐啊
在講動態代理之前先做一個很好理解的靜態代理的小例子:
說到代理,很容易想到的就是中介,例如房屋中介,不僅代替房東(房東本人也可以講房屋出租給客戶)將房屋出租給客戶(基本業務接口),還收取了中介費,轉化爲代碼
房租出租業務接口:
public interface RentInterface {
public void rent();
}
房東實現房屋出租:
public class Host implements RentInterface{
public void rent() {
System.out.println("房屋出租");
}
}
中介實現房屋出租:
public class HouseProxy implements RentInterface {
private Host host;
public void setHost(Host host) {
this.host = host;
}
//構造方法
public HouseProxy(Host host) {
super();
this.host = host;
}
@Override
public void rent() {
//不僅實現了房屋出租還收取了中介費
host.rent();
System.out.println("收取中介費");
}
}
客戶從代理那裏租房:
public class client {
public static void main(String[] args) {
System.out.println("客戶來了");
Host host=new Host();
HouseProxy houseProxy=new HouseProxy(host);
houseProxy.rent();
}
}
運行結果:
可以看到使用靜態代理的明顯優點是不僅可以實現原來的業務接口,還能添加些屬於自己的的業務,使得原來的業務接口更加純粹
缺點:一個業務接口需要一個代理實現類,增加開發代碼量
接着便是靜態代理的升級版——動態代理
主要有兩種實現方式:
1、基於接口的動態代理——jdk動態代理
2、基於類的動態代理——cglib
這裏主要講jdk動態代理
先看下API文檔說明(其實我看了也真的不理解)
則之前的靜態代理代碼中只需要改動:
public class HouseProxy implements InvocationHandler {
private Object target;
public void setTarget(Object target) {
this.target = target;
}
public Object getProxy() {
/**
* 返回一個指定接口的代理類實例,該接口可以將方法調用指派到指定的調用處理程序。
* newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)
*@param loader定義代理類的類加載器
*@param interfaces - 代理類要實現的接口列表
*@param h - 指派方法調用的調用處理程序
* */
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
Object result = method.invoke(target, args);
return result;
}
public void log(String methodName){
System.out.println("調用了"+methodName+"方法");
}
}
public class client {
public static void main(String[] args) {
System.out.println("客戶來了");
/*Host host=new Host();
HouseProxy houseProxy=new HouseProxy(host);
houseProxy.rent();*/
Host host=new Host();
HouseProxy proxy = new HouseProxy();
proxy.setTarget(host);
RentInterface host2=(RentInterface)proxy.getProxy();
host2.rent();
}
}
爲了更好的理解,我們再引入一個業務接口賣東西:
public interface SellInterface {
public void sell();
}
超市實現商品銷售:
public class Market implements SellInterface{
public void sell() {
System.out.println("賣商品");
}
}
客戶即可以通過代理實現房屋出租,也可以買東西public class client {
public static void main(String[] args) {
System.out.println("客戶來了");
/*Host host=new Host();
HouseProxy houseProxy=new HouseProxy(host);
houseProxy.rent();*/
Host host=new Host();
HouseProxy proxy = new HouseProxy();
proxy.setTarget(host);
RentInterface host2=(RentInterface)proxy.getProxy();
host2.rent();
Market market = new Market();
proxy.setTarget(market);
SellInterface sellInterface=(SellInterface)proxy.getProxy();
sellInterface.sell();
}
}
不難發現,相比於靜態代理,動態代理大大實現了代碼簡化及高效利用,無論有多少個業務接口,只要一個動態代理實例都能進行實現
動態代理其實它的編碼思想是一種代理模式,對於項目來說,公共的必不可少單獨實現又繁瑣的業務都可以利用動態代理來實現,如日誌、事物、緩存、安全權限、異常處理……