前言:
在開發(fā)中一定被老大這樣說過不要隨意去修改別人已經(jīng)寫好的代碼或者方法。但我們又希望原來的對象可以得到擴(kuò)展,又能保護(hù)原對象,這時代理模式就出來了。
在百科中這樣描述(定義):為其他對象提供一種代理以控制對這個對象的訪問。在某些情況下,一個對象不適合或者不能直接引用另一個對象,而代理對象可以在客戶端和目標(biāo)對象之間起到中介的作用。aop的實現(xiàn)對方法前后進(jìn)行攔截,改變原有對象或方法都是基于代理模式。代理模式分為靜態(tài)代理和jdk動態(tài)代理。
靜態(tài)代理
需求:張三看上了妹子,怕被拒絕而苦惱,于是李四說我替你把她約出來。
- 定義代理和被代理的公共的接口
//張三和李四的公共行為
public interface Person {
void meetGirl();
}
- 實現(xiàn)person接口,即具體動作的實現(xiàn)
//動作的具體實現(xiàn)
public class Man implements Person{
private String name;
public Man(String name){
this.name = name;
}
@Override
public void meetGirl() {
System.out.println(name+"正在和女孩吃飯,感謝你李四");
}
}
- 持有一個被代理對象的代理類,同樣要實現(xiàn)person接口
//man代理類
public class ManProxy implements Person {
//被代理的對象
private Man man;
//代理
public ManProxy(Person man){
this.man = (Man) man;
}
//被代理的執(zhí)行接口方法
@Override
public void meetGirl() {
man.meetGirl();
}
}
- client 測試,李四替張三約妹子
//代理的測試類
public class ProxyClient {
@Test
public void test(){
//被代理的對象
Person zhangsan = new Man("張三");
//生成代理對象李四 幫張三去約姑娘,把張三傳給代理對象
Person lisi = new ManProxy(zhangsan);
lisi.meetGirl();
}
}

動態(tài)代理參考
代理類在程序運(yùn)行時創(chuàng)建的代理方式被成為動態(tài)代理(生成相應(yīng)的class文件在加入jvm)。 我們上面靜態(tài)代理的例子中,代理類(ManProxy實現(xiàn)了接口和業(yè)務(wù)調(diào)用)是自己定義好的,在程序運(yùn)行之前就已經(jīng)編譯完成。然而動態(tài)代理,代理類并不是在代碼中定義的,而是在運(yùn)行時根據(jù)我們在代碼中的“指示”動態(tài)生成的, 動態(tài)代理的優(yōu)勢在于可以很方便的對代理類的函數(shù)進(jìn)行統(tǒng)一的處理,而不用修改每個代理類中的方法。動態(tài)代理分為兩種,一種分為基于接口的jdk代理;另一種則是基于類的代理如cglib(spring aop 實現(xiàn)),javassist等。
jdk 動態(tài)代理
JVM根據(jù)傳進(jìn)來的 業(yè)務(wù)實現(xiàn)類對象 以及 方法名 ,動態(tài)地創(chuàng)建了一個代理類的class文件并被字節(jié)碼引擎執(zhí)行,然后通過該代理類對象進(jìn)行方法調(diào)用。我們需要做的,只需指定代理類的預(yù)處理、調(diào)用后操作;在java的java.lang.reflect包下提供了一個Proxy類和一個InvocationHandler接口,實現(xiàn)InvocationHandler接口就可以生成被代理的對象。
- 假如如以上person 接口不變
- 業(yè)務(wù)邏輯的具體實現(xiàn)
public class RealPerson implements Person {
@Override
public void meetGirl() {
System.out.println("他們說你最美,來自jdk動態(tài)代理");
}
}
3 . 實現(xiàn)InvocationHandler接口定義代理類
//實現(xiàn)invocationHandler 接口的jdk動態(tài)代理類
public class SubjectHandler implements InvocationHandler {
//被代理的對象,包含相應(yīng)的業(yè)務(wù)方法
private Object target;
//綁定被代理的對象
public SubjectHandler(Object target){
this.target = target;
}
// //或者如下調(diào)用是會更加簡單 直接new SubjectHandler.bind(targect)
// public Object bind(Object target) {
// this.target = target; //接收業(yè)務(wù)實現(xiàn)類對象
//
// //通過反射機(jī)制,創(chuàng)建一個代理類對象實例并返回。用戶進(jìn)行方法調(diào)用時使用
// //創(chuàng)建代理對象時,需要傳遞該業(yè)務(wù)類的類加載器、接口、handler實現(xiàn)類
// return Proxy.newProxyInstance(target.getClass().getClassLoader(),
// target.getClass().getInterfaces(), this);
// }
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//具體要執(zhí)行的邏輯
Object result = null;
System.out.println("代理前的操作-----");
//合并邏輯,并通過return決定是否執(zhí)行
result = method.invoke(target,args);
System.out.println("方法處理后的操作-----");
//執(zhí)行后續(xù)操作
return result;
}
}
- 測試
public class JdkProxyClient {
@Test
public void test(){
//需要代理的目標(biāo)對象
RealPerson realPerson = new RealPerson();
//攔截器
SubjectHandler interceptor = new SubjectHandler(realPerson);
//生成代理類對象,執(zhí)行代理類的業(yè)務(wù)方法
//newProxyInstance 參數(shù):1.目標(biāo)類的加載器 2.目標(biāo)類接口 3.攔截器(處理的類)
Person person = (Person) Proxy.newProxyInstance(realPerson.getClass().getClassLoader(),realPerson.getClass().getInterfaces(),interceptor);
//執(zhí)行代理的業(yè)務(wù)方法
person.meetGirl();
}
}
spring 中的cglib 動態(tài)代理
JDK動態(tài)代理的代理對象在創(chuàng)建時,需要根據(jù)接口內(nèi)的方法名進(jìn)行調(diào)用,如果業(yè)務(wù)實現(xiàn)類是沒有實現(xiàn)接口或者業(yè)務(wù)實現(xiàn)類中新增了接口中沒有的方法,就無法使用JDK動態(tài)代理了(因為無法被調(diào)用),spirng 的cglib是針對實現(xiàn)代理的需要實現(xiàn)MethodInterceptor 接口
- 假設(shè)以上實現(xiàn)類不變,接口可有可無,則定義代理類如下
//基于spring 的cglib的動態(tài)代理
public class CglibInterceptor implements MethodInterceptor {
//代理對象
private Object target;
//綁定被代理的對象
public Object createProxyObject(Object obj) {
this.target = obj;
//創(chuàng)建代理類
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(obj.getClass());
enhancer.setCallback(this);
Object proxyObj = enhancer.create();
return proxyObj;// 返回代理對象
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object result = null;
//執(zhí)行業(yè)務(wù)邏輯
System.out.println("我是cglib代理");
//合并邏輯
result = method.invoke(target,objects);
return result; //返回結(jié)果
}
}
- 測試
public class CglibProxyClient {
@Test
public void test(){
//目標(biāo)對象
RealPerson realPerson = new RealPerson();
//攔截器
CglibInterceptor cglibInterceptor = new CglibInterceptor();
//獲得代理對象,區(qū)別jdk動態(tài),不需要接口
RealPerson cglib = (RealPerson) cglibInterceptor.createProxyObject(realPerson);
cglib.meetGirl();
}
}

總結(jié)
1.JDK動態(tài)代理只能對實現(xiàn)了接口的類生成代理,通過Proxy.newProxyInstance產(chǎn)生代理對象而不能針對類。
2.CGLIB是針對類實現(xiàn)代理,主要是對指定的類生成一個子類,覆蓋其中的方法