設計模式之代理模式(Proxy Pattern)
阿新 • • 發佈:2018-12-11
應用場景
Proxy代理模式是一種結構型設計模式,主要解決的問題是:直接訪問物件時帶來的問題。
為了保持行為的一致性,代理類和委託類通常會實現相同的介面,所以在訪問者看來兩者並無區別。
代理類種類:
靜態:建立代理類再對其編譯,在程式執行前代理類的.class檔案就已經存在了。
動態:在程式執行時運用反射機制動態建立而成。
一、靜態代理
靜態代理實現很簡單,就是跟目標類實現同樣的介面,然後引入目標類。在目標類方法執行前後增加額外的方法即可。
但是有個問題需要注意:每次在介面中新增一個新方法,則需要在目標物件中實現這個方法,並且在代理物件中實現相應的代理方法。
public interface ProductDao { //新增商品 void add(); //刪除商品 void delete(); //修改商品 void update(); //查詢商品 void select(); }
public class ProductDaoImpl implements ProductDao { @Override public void add() { System.out.println("目標物件中新增商品"); } @Override public void delete() { System.out.println("目標物件中刪除商品"); } @Override public void update() { System.out.println("目標物件中修改商品"); } @Override public void select() { System.out.println("目標物件中查詢商品"); } }
public class ProductDaoImplProxy implements ProductDao { private ProductDaoImpl productDaoImpl; public ProductDaoImplProxy(ProductDaoImpl productDaoImpl) { super(); this.productDaoImpl = productDaoImpl; } @Override public void add() { System.out.println("新增商品begin"); productDaoImpl.add(); } @Override public void delete() { System.out.println("刪除商品begin"); productDaoImpl.delete(); } @Override public void update() { System.out.println("修改商品begin"); productDaoImpl.update(); } @Override public void select() { System.out.println("刪除商品"); productDaoImpl.delete(); } }
二、動態代理
常見的動態代理有JDK動態代理跟Cglib動態代理
1.JDK動態代理
JDK的動態代理,是使用反射技術獲得類的載入器並且建立例項,根據類執行的方法在執行方法的前後傳送通知。
java.lang.reflect 包下面的Proxy類和InvocationHandler 介面提供了生成動態代理類的能力。
在代理物件Proxy的新建代理例項方法中,必須要獲得類的載入器、類所實現的介面、還有一個攔截方法的控制代碼。然後在控制代碼的invoke()方法中呼叫method.invoke(),在此方法前後傳送通知,實現功能擴充套件。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProductDaoJDKProxy {
public static void main(String[] args) {
//目標物件
ProductDao productDao = new ProductDaoImpl();
//代理物件
ProductDao proxy = (ProductDao) Proxy.newProxyInstance(
productDao.getClass().getClassLoader(),
productDao.getClass().getInterfaces(),
new InvocationHandler() {
//攔截到目標物件的方法時執行
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("jdk在代理物件中攔截到方法:" + method.getName());
proxy = method.invoke(productDao, args);
return proxy;
}
});
//代理物件呼叫方法
proxy.add();
proxy.delete();
}
}
執行結果:
2.Cglib動態代理
JDK動態代理和靜態代理所代理的類都是實現了某介面的,對於沒有實現介面的類,可以使用Cglib動態代理。
Cglib動態代理需要引入兩個jar包:asm跟cglib
注意:arg0:生成的代理物件;arg1:目標物件的方法;arg2:目標物件的方法入參
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class ProductDaoCglibProxy {
public static void main(String[] args) {
ProductDaoImpl target = new ProductDaoImpl();
Enhancer enhancer = new Enhancer();
// 設定代理物件的父類
enhancer.setSuperclass(target.getClass());
// 設定回撥
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
System.out.println("Cglib在代理物件中攔截到方法:" + arg1.getName());
arg0 = arg1.invoke(target, arg2);
return arg0;
}
});
// 代理物件呼叫方法
ProductDaoImpl proxy = (ProductDaoImpl) enhancer.create();
proxy.add();
proxy.delete();
}
}
執行結果: