從開始java學習到從事java工作這麼多時間以來,對代理模式的概念和現實已經瞭解的比較清楚了,但是一直不知道它的應用場景到底是什麼樣的,網上的資料無非就是對方法的增強或者增加日誌操作什麼的,我想這些操作我做個包裝類,在這個類中做這些處理不是一樣嗎?
先說說概念:靜態代理、動態代理、cglib
靜態代理:實例和代理類都實現了同一個接口,不管傳遞什麼實例進代理類中都能調用方法,不需要在每個新生成的實例中重複寫某一個方法
Java動態代理類位於java.lang.reflect包下,一般主要涉及到以下兩個類:
(1) Interface InvocationHandler:該接口中僅定義了一個方法
public objectinvoke(Object obj, Methond method, Object[] args)在實際使用時,第一個參數obj一般是指代理類,method是被代理的方法,args爲該方法的參數數組。
(2) Proxy:該類即爲動態代理類
static ObjectnewProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)返回代理類的一個實例,返回後的代理類可以當作被代理類使用(可使用被代理類在接口中聲明過的方法)
3 cglib也是動態代理,不同於proxy,它不需要基於接口進行代理
代理模式的優點:
1、代理模式能夠協調調用者和被調用者,在一定程度上降低了系統的耦合度;
2、代理對象可以在客戶端和目標對象之間起到中介的作用,這樣起到了保護目標對象的作用
3、還有一個我認爲的優點、使用代理類我們就可以不用管委託類方法中的變動,或者我們只需要做少量的調整,比如如果委託類中的某個方法突然改成私有了,那個不使用代理類我們需要在每個此方法調用的地方都要把反射處理才能調用,使用代理之後 我們只需要在代理類中處理就可以了,當然這些操作可以使用包裝類做,但是問題就在於我們不知道哪個方法會變成私有,不可能每個方法都寫個包裝類進行反射處理。
缺點:
1、由於在客戶端和真實對象之間增加了代理對象,因此有些類型的代理模式可能會造成請求的處理速度變慢;
2、實現代理模式需要額外的工作,有些代理模式的實現非常複雜。
3、靜態代理在委託類變多的情況時會顯的非常臃腫,不方便閱讀與使用
最近研究了一下應用場景,說說我的理解吧,如果不對請大家指出。
1:類中的方法批量處理
2:方法的區分處理
3:當我們想要隱藏某個類,或者這個類中的部分方法
4:擴展功能
1 ===> 假如一個類中的方法有100個,我們想要對這些方法都做日誌處理。這個時候我們就可以使用代理,簡化代碼,不需要在每個方法調用的時候都做日誌處理。
2====> 基於委託類中的這100個方法,其中有50個方法我想做日誌處理,另外40個方法我想做執行時間輸出,另10個我不想做處理的時候用代理也是挻好的
3====> 如果某個類我想隱藏,但是每些方法又想給其它人使用就可以使用代理。這些隱藏又如私有化構造,或者內部類等。
4====> 擴展功能也是常說的功能,對方法進行增強等操作,對不同的權限進行不同的增強......
下面介紹一下cglib中的實現,參考https://www.cnblogs.com/xrq730/p/6661692.html
public class DaoFilter implements CallbackFilter {
@Override
public int accept(Method method) {
if ("select".equals(method.getName())) {
return 0; //這裏返回的數字對應的是callback中的代理位置
}
return 1;
}
}
@Test
public void testCglib() {
DaoProxy daoProxy = new DaoProxy();
DaoAnotherProxy daoAnotherProxy = new DaoAnotherProxy(); //兩個不同的代理
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Dao.class);
enhancer.setCallbacks(new Callback[]{daoProxy, daoAnotherProxy, NoOp.INSTANCE});//代理中的位置0,1,2
enhancer.setCallbackFilter(new DaoFilter());
Dao dao = (Dao)enhancer.create();
dao.update(); //update對應filter中的1,所以會使用daoAnotherProxy代理
dao.select(); //select對應filter中的0,所以會使用daoProxy代理
//如果有個方法不想做處理就可以讓filter返回2,這個就是使用NoOp.INSTANCE不做處理
}
通常構造方法中對委託類的調用也會走代理,cglib中可以設置對構造方法中方法調用不使用代理
@Test
public void testCglib() {
DaoProxy daoProxy = new DaoProxy();
DaoAnotherProxy daoAnotherProxy = new DaoAnotherProxy();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Dao.class);
enhancer.setCallbacks(new Callback[]{daoProxy, daoAnotherProxy, NoOp.INSTANCE});
enhancer.setCallbackFilter(new DaoFilter());
enhancer.setInterceptDuringConstruction(false); //===>此處默認是true,設置false後,構造方法中方法的調用不走代理
Dao dao = (Dao)enhancer.create();
dao.update();
dao.select();
}
此外還可以使用泛型,對不同的委託進行代理
public class CglibTest<T> {
public T aaa(T t) {
return t;
}
public void testCglib(T o,Class c) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
DaoProxy daoProxy = new DaoProxy();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(c);
// enhancer.setCallbacks(new Callback[]{daoProxy,NoOp.INSTANCE});
enhancer.setCallback(daoProxy);
@SuppressWarnings("unchecked")
T dao = (T)enhancer.create();
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method.getName());
method.invoke(dao);
}
}
public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Dao dao = new Dao();
CglibTest<Dao> c = new CglibTest<>();
c.testCglib(dao, dao.getClass());
}
}