動態代理是JAVA的一大特性。
動態代理的優勢就是實現無浸入式的代碼擴展。
目前動態代理主要分為JAVA自己提供的動態代理和CGLIB類似框架。(本文只說JAVA自己提供的動態代理)
JAVA自帶的動態代理是需要接口的。CGLIB這種則是直接修改字節碼。
在學習Java動態代理之前,我們需要明白靜態代理是怎么實現的,怎么說呢,動態代理是更優雅的實現代理模式。只有了解靜態代理的不足之處,才能更好的運用動態代理。靜態代理對于重復代碼的解決很差勁,每一個override的方法都會有重復代碼。如果一個項目有成百上千個Bean的話,豈不是要造很多靜態代理類么?所以動態代理就出現了。
什么是代理模式?
代理模式的作用是:為其他對象提供一種代理以控制這個對象的訪問。
代理模式有什么好處?
在某些情況下,一個客戶不想或者不能直接引用另一個對象,而代理對象可以在客戶端和目標對象之間起到中介作用。
代理模式一般涉及的角色有?
抽象角色:聲明真實對象和代理對象的共同接口,這樣一來在任何可以使用目標對象的地方都可以使用代理對象。
代理角色:代理對象內部含有目標對象的引用,從而可以在任何時候操作目標對象;代理對象提供一個與目標對象相同的接口,以便可以在任何時候替代目標 對象。代理對象通常在客戶端調用傳遞給目標對象之前或之后,執行某個操作,而不是單傳地將調用傳遞給目標對象,同時,代理對象可以在執行真實對象操作時,附加其他的操作,相當于對真實對象進行封裝。
真實角色:定義了代理對象所代表的目標對象,代理角色鎖代表的真實對象,是我們最終要引用的對象,定義了代理對象所代表的目標對象。
抽象角色:
<pre>public abstract class AbstractObject {
//操作
public abstract void operation();
}</pre>
真實角色:
<pre>
public class RealObject extends AbstractObject {
@Override
public void operation() {
//一些操作
System.out.println("一些操作");
}
}
</pre>
代理角色:
<pre>
public class ProxyObject extends AbstractObject{
RealObject realObject = new RealObject();
@Override
public void operation() {
//調用目標對象之前可以做相關操作
System.out.println("before");
realObject.operation();
//調用目標對象之后可以做相關操作
System.out.println("after");
}
}
</pre>
<pre>public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
AbstractObject obj = new ProxyObject();
obj.operation();
}
}
</pre>
以上是靜態代理的實現,接下來才是進入正題了,Java的動態代理。
什么是動態代理?
代理類是在程序運行前不存在,運行時由程序動態生成的代理方式稱為動態代理。
Java提供了動態代理的實現方式,可以在運行時刻動態生成代理類。這種代理方式的一大好處是可以方便對代理類的函數做統一或特殊處理,如記錄所有函數執行時間,所有函數執行前添加驗證判斷,對某個特殊函數進行特殊操作,而不用像靜態代理方式那樣需要修改每個函數。
動態代理實例
實現動態代理包括散步:
1.新建委托類;
2.實現InvocationHandler接口,這是負責連接代理類和委托類的中間類必須實現的接口;
3.通過Proxy類新建代理類對象。
1-新建委托類
<pre>
public interface UserService{
public String getName(int id);
public Integer getAge(int id);
}
public class UserServiceImpl implements UserService {
@Override
public String getName(int id) {
System.out.println("------getName------");
return "Tom";
}
@Override
public Integer getAge(int id) {
System.out.println("------getAge------");
return 10;
}
}
</pre>
UserService是一個接口,定義了一些函數。
UserServiceImpl是委托類,實現了UserService接口,每個函數只是簡單的輸出字符串。動態代理要求委托類必須實現了某個接口,比如這里委托類UserServiceImpl實現了UserService。
2-實現InvocationHandler接口
<pre>
public class MyInvocationHandler implements InvocationHandler {
private Object target;
MyInvocationHandler() {
super();
}
MyInvocationHandler(Object target) {
super();
this.target = target;
}
@Override
public Object invoke(Object o, Method method, Object[] args) throws Throwable {
if("getName".equals(method.getName())){
System.out.println("++++++before " + method.getName() + "++++++");
Object result = method.invoke(target, args);
System.out.println("++++++after " + method.getName() + "++++++");
return result;
}else{
Object result = method.invoke(target, args);
return result;
}
}
}
</pre>
target屬性表示委托類對象。
InvocationHandler是負責連接代理類和委托類的中間類必須實現的接口。其中只有一個
<pre>public Object invoke(Object proxy, Method method, Object[] args)</pre>
函數需要去實現,參數:
proxy表示Proxy.newProxyInstance()生成的代理類對象。
method表示代理對象被調用的函數。
args表示代理對象被調用的函數的參數。
調用代理對象的每個函數實際最終都是調用了InvocationHandler的invoke函數。這里我們在invoke實現中添加了一些代碼片。
invoke函數中我們也可以通過method做一些判斷,從而對某些函數特殊處理。
3-通過Proxy類靜態函數生成代理對象
<pre>public class Main1 {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
InvocationHandler invocationHandler = new MyInvocationHandler(userService);
UserService userServiceProxy = (UserService)Proxy.newProxyInstance(userService.getClass().getClassLoader(),
userService.getClass().getInterfaces(), invocationHandler);
System.out.println(userServiceProxy.getName(1));
System.out.println(userServiceProxy.getAge(1));
}
} </pre>
這里我們先將委托類對象new UserServiceImpl()
作為MyInvocationHandler
構造函數入參創建invocationHandler
對象;然后通過Proxy.newProxyInstance(…)
函數新建了一個代理對象,實際代理類就是在這時候動態生成的。我們調用該代理對象的函數就會調用到invocationHandler
的invoke
函數(是不是有點類似靜態代理),而invoke
函數實現中調用委托類對象new UserServiceImpl()
相應的 method(是不是有點類似靜態代理)。
<pre>public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)</pre>
loader表示類加載器
interfaces表示委托類的接口,生成代理類時需要實現這些接口
h是InvocationHandler實現類對象,負責連接代理類和委托類的中間類
我們可以這樣理解,如上的動態代理實現實際是雙層的靜態代理,開發者提供了委托類 B,程序動態生成了代理類 A。開發者還需要提供一個實現了InvocationHandler的子類 C,子類 C 連接代理類 A 和委托類 B,它是代理類 A 的委托類,委托類 B 的代理類。用戶直接調用代理類 A 的對象,A 將調用轉發給委托類 C,委托類 C 再將調用轉發給它的委托類 B。
在Android的使用場景
基于 REST 的 Android 端網絡請求框架 Retrofit
作用:簡化網絡請求操作。一般情況下每個網絡請求我們都需要調用一次HttpURLConnection
或者HttpClient
進行請求,或者像 Volley 一樣丟進等待隊列中,Retrofit 極大程度簡化了這些操作,示例代碼如下:
<pre>public interface GitHubService {
@GET("/users/{user}/repos")
List<Repo> listRepos(@Path("user") String user);
}
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint("https://api.github.com")
.build();
GitHubService service = restAdapter.create(GitHubService.class);</pre>
以后我們只需直接調用
<pre>List<Repo> repos = service.listRepos("octocat");</pre>
即可開始網絡請求,Retrofit
的原理就是基于動態代理,它同時用到了 注解 的原理,本文不做深入介紹,具體請等待 Retrofit 源碼解析 完成。