什么是java代理
代理是設(shè)計模式的一種,其原理就是通過代理對象去訪問目標對象,而外部只能訪問到代理對象
在編程中有這么一種思想,你不要隨便的去修改已經(jīng)寫好的代碼,如需修改,那么可以通過代理來擴展類的功能。
<a name="z7z8I"></a>
靜態(tài)代理
什么是靜態(tài)代理,靜態(tài)代理就是你定義一個接口或者是父類,然后代理類與被代理類都需要繼承這個接口,在代理類中實現(xiàn)一個方法,需要注入被代理類,這樣就能通過代理類去訪問被代理類,同時,也可以對被代理類進行增強。
上代碼:
/**
* 定義一個接口,包含一個方法,吃
*/
public interface Person {
void eat();
}
/**
* 實現(xiàn) Person
* 這個是一個實際的目標類,當前類實現(xiàn)一個吃的方法
*/
public class Man implements Person {
public void eat() {
System.out.println("吃飯");
}
}
/**
* Man對象的代理,當前代理持有一個Man的對象
*/
public class ManProxy implements Person {
private Person target;
public ManProxy(Person target){
this.target = target;
}
public void eat() {
System.out.println("吃冷菜");
target.eat();
System.out.println("吃甜品");
}
}
/**
* 測試
*/
public class App {
public static void main(String[] args) {
Person target = new Man();
Person manProxy = new ManProxy(target);
manProxy.eat();
}
}
結(jié)果:
吃冷菜
吃飯
吃甜品
以上就是一個典型的靜態(tài)代理的例子,在當前的例子里,有一個Person的接口,該接口的主要作用是定義一個代理類和被代理類都擁有的行為,當前的行為為eat
代理類和被代理類都實現(xiàn)了Person,不過不同的是,代理類持有了一個被代理類的對象,在代理類中可以執(zhí)行被代理類的方法,因此在代理類中可以在該方法的基礎(chǔ)上進行擴展。
缺點:由于代理類需要實現(xiàn)與被代理類同一個接口,那么不同的被代理類就需要去實現(xiàn)不同的接口,那么就會出現(xiàn)代理類很難復(fù)用的情況,相對的維護成本也難以控制。
<a name="ZeuqT"></a>
動態(tài)代理
什么是動態(tài)代理,動態(tài)代理就是利用JDK的API動態(tài)的在內(nèi)存中構(gòu)建代理對象,因此,動態(tài)代理也叫做JDK代理,或者接口代理,在動態(tài)代理中,代理對象不需要實現(xiàn)接口,但是被代理對象還是需要實現(xiàn)對象的。
<a name="88hpa"></a>
生成代理對象的API
生成代理對象的API主要的包在java.lang.reflect.Proxy
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )
參數(shù)說明:<br />ClassLoader loader : 該參數(shù)是被代理對象的使用的類加載器,這個我們直接通過被代理對象就可以獲取
Class<?>[] interfaces : 被代理對象實現(xiàn)的接口,這個也可以通過被代理對象獲取
InvocationHandler h : 當我們在執(zhí)行被代理對象的方法的時候,這個處理器就會被執(zhí)行,當這個方法被執(zhí)行的時候,會將被代理對象,方法,參數(shù)都傳入進去
上代碼:
/**
* 代理工廠
* 主要作用是生成代理對象
*/
public class ProxyFactory {
//被代理對象
private Object target;
public ProxyFactory(Object target){
this.target = target;
}
//為被代理對象生成代理對象
public Object getProxyInstance(){
return Proxy.newProxyInstance(
//指定當前被代理對象使用的類加載器
target.getClass().getClassLoader(),
//指定被代理對象實現(xiàn)的接口類型,這里是一個數(shù)組,代理可能實現(xiàn)多個接口
target.getClass().getInterfaces(),
//事件處理,當我們在執(zhí)行被代理對象的方法的時候,會觸發(fā)這個處理器,會把當前執(zhí)行的被代理對象的方法作為參數(shù)傳入進去
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("執(zhí)行前置方法");
//執(zhí)行目標方法
Object returnValue = method.invoke(target, args);
System.out.println("執(zhí)行后置方法");
return returnValue;
}
}
);
}
}
public class App {
public static void main(String[] args) {
//被代理對象
Person target = new Man();
System.out.println("被代理對象打印:"+target.getClass());
//創(chuàng)建代理對象
Person proxy = (Person) new ProxyFactory(target).getProxyInstance();
System.out.println("代理對象打?。?+proxy.getClass());
proxy.eat();
}
}
結(jié)果:
被代理對象打?。篶lass com.luban.aop.proxy.statics.Man
代理對象打?。篶lass com.sun.proxy.$Proxy0
執(zhí)行前置方法
吃飯
執(zhí)行后置方法
缺點:在動態(tài)代理中,代理對象不需要再實現(xiàn)接口了,但是被代理對象還是需要實現(xiàn)接口,否則就無法使用動態(tài)代理
<a name="V4EnP"></a>
Cglib代理
什么是cglib代理,無論是動態(tài)代理還是靜態(tài)代理,都要求我們的被代理的對象必須要實現(xiàn)某一個接口,但是也可能存在這樣的情況,一個類沒有實現(xiàn)任何的接口,這個時候就可以使用cglib代理。
cglib代理是通過被代理對象的子類的形式來實現(xiàn)代理的,他會在內(nèi)存中構(gòu)建一個被代理對象的子類對象,來實現(xiàn)對被代理對象的功能的擴展。
在cglib的底層是通過一個字節(jié)碼處理框架ASM來轉(zhuǎn)換字節(jié)碼生成新的類
如果需要使用cglib的話,需要引入一個包 cglib
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
上代碼
/**
* 被代理類
*/
public class Woman {
public void eat(){
System.out.println("吃飯");
}
}
/**
* cglib 代理工廠類
*/
public class ProxyFactory implements MethodInterceptor {
//被代理對象
private Object target;
public ProxyFactory(Object target){
this.target = target;
}
//為被代理對象創(chuàng)建一個代理對象
public Object getProxyInstance(){
//這個是工具類
Enhancer en = new Enhancer();
//將被代理類設(shè)置為父類
en.setSuperclass(target.getClass());
//設(shè)置回調(diào)
en.setCallback(this);
//創(chuàng)建子類(代理對象)
return en.create();
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("前置執(zhí)行....");
//執(zhí)行被代理類的方法
Object returnValue = method.invoke(target,objects);
System.out.println("后置執(zhí)行....");
return returnValue;
}
}
public class App {
public static void main(String[] args) {
//被代理對象
Woman target = new Woman();
//代理對象
Woman proxy = (Woman) new ProxyFactory(target).getProxyInstance();
//執(zhí)行方法
proxy.eat();
}
}
執(zhí)行結(jié)果:
前置執(zhí)行....
吃飯
后置執(zhí)行....
注意:被代理對象的方法不能用final或者static
在springAOP中,如果被代理對象沒有實現(xiàn)接口則使用cglib,如果實現(xiàn)了接口則使用動態(tài)代理
免費在線視頻學(xué)習(xí),請訪問(持續(xù)更新中):java 教程 - 免費分享的視頻教程
更多的資訊請訪問QQ群:807167416