設計模式之代理模式
- 2020 年 7 月 7 日
- 筆記
- Design Patterns
代理模式
- 作用:在不改變原有程式碼的基礎上,增加或擴展額外的功能
- 靜態代理
//1,被代理類需要實現的介面,代理類也要實現該介面,該介面對用戶使用
interface FlightMachine{
void fly();
}
//2,被代理類實現介面
class FlightMachineImpl implements FlightMachine{
@Override
public void fly() {
System.out.println("我可以飛");
}
}
//3,代理類實現介面
class FlightProxy implements FlightMachine{
//4,代理類引用被代理對象
private FlightMachine flightMachine;
//5,寫有參構造方法得到被代理對象實例
public FlightProxy(FlightMachine flightMachine){
super();
this.flightMachine=flightMachine;
}
@Override
public void fly() {
//增加額外的功能
System.out.println("我可以發射導彈");
flightMachine.fly();
//增加額外的功能
System.out.println("我可以航拍");
}
}
public class TestProxy {
public static void main(String[] args) {
FlightMachine flightMachine = new FlightMachineImpl();
FlightMachine flightProxy = new FlightProxy(flightMachine);
flightProxy.fly();
}
}
console:
我可以發射導彈
我可以飛
我可以航拍
小結:代理類和被代理類都需要實現同一個介面,且代理類預先設定,造成服務單一,要是其他類需要代理則需要更多代理類,不易擴展,缺點比較明顯,適用場景不廣。
- 動態代理
- JDK代理
- 使用JDK自帶的代理類,製造代理工廠
- 使用JDK自帶的代理類,製造代理工廠
- JDK代理
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//1,被代理類實現的介面
interface FlightMachine{
void fly();
}
//2,被代理類需要至少實現的一個介面
class FlightMachineImpl implements FlightMachine{
@Override
public void fly() {
System.out.println("我可以飛");
}
}
//3,創建動態代理的工廠類,用來動態生成代理類對象
class FlightProxyFactory{
//4,需要引用被代理的對象
private Object target;
//5,寫有參構造方法得到代理目標實例
public FlightProxyFactory(Object target) {
this.target = target;
}
//6,提供一個獲取代理類對象的方法
public Object getProxyInstance(){
//用JDK自帶的reflect包的Proxy創建代理類實例
/*
@Proxy.newProxyInstance(Param1,Param2,Param3){ }
參數1:類載入器,一般一個項目只有一個類載入器,所以選取比較方便獲取的類來getClassLoader()就行
參數2:代理目標所實現的所有介面,通過.getClass().getInterfaces()獲得
參數3:方法調用處理器
*/
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), new InvocationHandler() {
/*
invoke(Param1,Param2,Param3){ }
參數1:代理類對象
參數2:被代理類(代理目標)需要執行的方法
參數3:執行方法需要的參數
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增加額外的功能
System.out.println("我可以發射導彈");
//通過反射來調用代理目標方法
Object procedure = method.invoke(target, args);
//增加額外的功能
System.out.println("我可以航拍");
return procedure;
}
});
}
}
public class TestProxy {
public static void main(String[] args) {
FlightMachine flightMachine = new FlightMachineImpl();
FlightProxyFactory flightProxyFactory = new FlightProxyFactory(flightMachine);
Object proxyInstance = flightProxyFactory.getProxyInstance();
if (proxyInstance instanceof FlightMachine){
FlightMachine machineProxy = (FlightMachine) proxyInstance;
machineProxy.fly();
}
}
}
console:
我可以發射導彈
我可以飛
我可以航拍
小結:建立代理工廠,根據需要的類動態生成代理類,雖然代理目標不固定,但是需要實現至少一個介面,不是所有的類都實現了介面或者繼承了某個類,所以還不夠好,但是JDK代理在反射生成代理類方面是作用較好,和其他動態代理方式配合使用效果更好。
- CGLIB代理
- 使用第三方代理包,cglib和asm兩個包需要引入,核心介面是MethodInterceptor,核心類是Enhancer,給被代理類動態生成一個子類來進行代理(子類對父類來說就相當於擴展了功能)
- 使用第三方代理包,cglib和asm兩個包需要引入,核心介面是MethodInterceptor,核心類是Enhancer,給被代理類動態生成一個子類來進行代理(子類對父類來說就相當於擴展了功能)
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
//1,被代理類
class FlightMachineImpl {
public void fly() {
System.out.println("我可以飛");
}
}
//2,創建cglib動態代理的工廠類,用來動態生成代理類、代理類對象,並實現MethodInterceptor介面
class CglibProxyInterceptor implements MethodInterceptor {
//3,引用代理目標的對象
private Object target;
//4,寫有參構造方法得到代理目標實例
public CglibProxyInterceptor(Object target) {
this.target = target;
}
//5,提供一個獲取代理類對象的方法
public Object getProxyInstance(){
//6,用cglib包的Enhancer創建代理類,且該代理類需要繼承代理目標成為其子類
Enhancer enhancer = new Enhancer();
//7,將代理目標設置為代理類的父類
enhancer.setSuperclass(target.getClass());
//8,設置回調函數
enhancer.setCallback(this);
//9,創建代理類對象
return enhancer.create();
}
//6,實現intercept方法
/*
@intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy){ }
參數1 o:被代理的對象
參數2 method:代理對象的方法,這裡是FlightMachineImpl的fly()方法
參數3 objects:方法的參數
參數4 methodProxy:方法代理,這裡代理的是cglib代理的fly()方法
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("我可以發射導彈");
Object result = method.invoke(target, objects);
System.out.println("我可以航拍");
//methodProxy的invokeSuper可以實現相同的效果
// Object result = methodProxy.invokeSuper(o, objects);
return result;
}
}
public class TestProxy {
public static void main(String[] args) {
CglibProxyInterceptor cglibProxyInterceptor = new CglibProxyInterceptor(new FlightMachineImpl());
Object proxyInstance = cglibProxyInterceptor.getProxyInstance();
if (proxyInstance instanceof FlightMachineImpl){
FlightMachineImpl flightMachine = (FlightMachineImpl) proxyInstance;
flightMachine.fly();
}
}
}
console:
我可以發射導彈
我可以飛
我可以航拍
小結:使用cglib代理,代理目標不用實現介面或繼承類,只需根據該被代理類生成子類作為其代理類完成代理,和JDK代理一起在spring aop中使用廣泛。
至此,若有紕漏,望各位不吝賜教