Proxy代理模式
代理模式基本概念:爲其他對象提供一個代理來控制這個的訪問。
主要解決的問題:直接訪問對象時所帶來的問題。
代理類: 負責爲委託類預處理消息,過濾消息並轉發消息,以及進行消息被委託類執行後的後續處理。
舉個栗子(=.=)
開始接觸spring框架的時候,必然的要去了解 IOC 和 AOP,其中AOP的底層實現原理就是動態代理。以此爲切入點,通過對AOP底層實現的理解,初識代理模式。
1、靜態代理實現AOP,首先來一波簡單代碼①
//目標對象的接口
public interface IWorkDao {
void work();
}
//實現類
public class WorkDaoImpl implements IWorkDao {
@Override
public void work() {
System.out.println("這裏是目標對象WorkDao的實現類");
}
}
//增強類:一般給類方法添加事務控制或者性能檢測
public class TransactionManager {
public void beginTransation(){
System.out.println("start...");
}
//切割線------
//...業務邏輯代碼
//切割線------
public void endTransation(){
System.out.println("over...");
}
}
目標對象增加的過程產生代理類
//代理對象持有被代理對象的一個接口public class WorkDaoProxy implements IWorkDao { //主角:目標對象 IWorkDao workDao; //配角:增強對象 TransactionManager tx; //來一個構造器 public WorkDaoProxy(IWorkDao workDao, TransactionManager tx) { this.workDao = workDao; this.tx = tx; } //將增強添加到目標對象(織入) @Override public void work() { tx.beginTransation();//非業務代碼 workDao.work(); //業務代碼 tx.endTransation();//非業務代碼,橫向切割體現出來了有木有 }}
//測試類
public class Test {
public static void main(String[] args) {
//目標對象
IWorkDao workDao = new WorkDaoImpl();
//增強
TransactionManager tx = new TransactionManager();
//代理對象
WorkDaoProxy workDaoProxy = new WorkDaoProxy(workDao,tx);
//代理對象調用目標方法
workDaoProxy.work();
}
}
這裏存在一個問題,要是我創建其他的目標對象接口比如ISleepDao或者修改當前類方法名,這不又得重新創建一個代理類或者修改?好麻煩有木有,所以就有以下方案:
2、基於jdk動態代理實現AOP(基於InvocationHandler接口模式),代碼①省略
//代理類
public class ProxyHandle implements InvocationHandler {
//目標對象(不用知道具體的目標對象是誰,好神祕)
Object target;
//增強
TransactionManager tx;
//構造器(用於實例化handle)
public ProxyHandle(Object target, TransactionManager tx) {
this.target = target;
this.tx = tx;
}
/**
* 織入
* @param proxy
* @param method
* @param args 參數列表
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
tx.beginTransation();
Object obj = method.invoke(target, args);
tx.endTransation();
return obj;
}
}
//測試類
public class Test {
public static void main(String[] args) {
//目標對象
IWorkDao workDao = new WorkDaoImpl();
//增強
TransactionManager tx = new TransactionManager();
//獲得handle(構造器開闢內存空間用於存放目標對象和增強對象)
ProxyHandle handle = new ProxyHandle(workDao,tx);
//生成代理對象(傳入handle,利用反射獲得目標對象和增強)
IWorkDao workDaoProxy = (IWorkDao) Proxy.newProxyInstance(workDao.getClass().getClassLoader(), workDao.getClass().getInterfaces(), handle);
//代理對象調用目標方法
workDaoProxy.work();
}
}
解決了每創建一個目標對象必須創建一個代理類的問題,JDK中的動態代理是通過反射類Proxy以及InvocationHandler回調接口實現的,但是,JDK中所要進行動態代理的類必須要實現一個接口(如上面的:Object target 的接口),也就是說只能對該類所實現接口中定義的方法進行代理,這在實際編程中具有一定的侷限性,而且使用反射的效率也並不是很高。
3、基於cglib動態代理實現AOP,首先要導入cglib的jar包,繼續代碼①省略
//代理類
public class CglibDynInterceptor implements MethodInterceptor{
//要代理的原始對象(拋棄你了)
//private Object object;
private Enhancer enhancer = new Enhancer();
private TransactionManager tx;
public CglibDynInterceptor(TransactionManager tx) {
this.tx = tx;
}
//創建子類
public Object getProxy(Class cls){
enhancer.setSuperclass(cls); //設置代理對象
enhancer.setCallback(this); //回調MethodInterceptor接口方法攔截(類似於JDK中的 InvocationHandler接口)
//通過字節碼技術動態創建子類
return enhancer.create();
}
/**
* object:由CGLib動態生成的代理類實例
* method:增強方法引用
* args:參數值列表
* methodProxy:生成的代理類對方法的代理引用
*/
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy)
throws Throwable {
tx.beginTransation();
//攔截父類方法(調用代理類實例上的proxy方法的父類方法)
Object result = methodProxy.invokeSuper(object, args);
tx.endTransation();
return result;
}
}
//測試類
public class Test {
public static void main(String[] args) {
//增強
TransactionManager tx = new TransactionManager();
//創建代理類
CglibDynInterceptor proxy = new CglibDynInterceptor(tx);
//通過反射創建代理對象(子類)
IWorkDao workDaoProxy = (IWorkDao) proxy.getProxy(IWorkDao.class);
workDaoProxy.work();
}
}
使用CGLib實現動態代理,完全不受代理類必須實現接口的限制,而且CGLib底層採用ASM字節碼生成框架,使用字節碼技術生成代理類,比使用Java反射效率要高。唯一需要注意的是,CGLib不能對聲明爲final的方法進行代理,因爲CGLib原理是動態生成被代理類的子類。
Enhancer允許爲非接口類型創建一個Java代理。Enhancer動態創建了給定類型的子類但是攔截了所有的方法。和Proxy不一樣的是,不管是接口還是類他都能正常工作(解決jdk動態代理中每創建一個代理類必須要實現接口)
另外:Callback接口是一個空接口,沒有任何契約方法,它只表示這是一個回調。
以上是個人結合SpringAop底層實現原理去理解代理模式,不足之處還請諒解~