国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
靜態(tài)代理與動態(tài)代理、CGLIB

代理:無論哪種代理,都存在代理對象和目標對象兩個模型,所以目標對象就是我們要生成的代理對象代理的那個對象。

 

一、包裝的動態(tài)代理

 

接口:

public interface Animal {

   void eat(String food);

   String type();

}

public interface Primate {

   void think();

}

實現(xiàn)類:

public class Monkey implements Animal,Primate{

   public void eat(String food) {

      System.out.println("the food is "+food+" !");

     

   }

   public String type() {

      String type="哺乳動物";

      System.out.println(type);

      return type;

   }

   public void think() {

      System.out.println("思考");

   }

}

 

包裝類的代理:

public class AnimalWrapper implements Animal{

   private Animal animal;

   public AnimalWrapper(Animal animal){

      this.animal=animal;

   }

  

   public void eat(String food) {

      System.out.println("+++Wrapped Before!+++");

      animal.eat(food);

      System.out.println("+++Wrapped After!+++");

   }

 

   public String type() {

      System.out.println("+++Wrapped Before!+++");

      String type=animal.type();

      System.out.println("+++Wrapped After!+++");

      return type;

   }

 

}

 

可以看到,AnimalWrapper完成了對Animal所有子類的代理,在代理方法中,可以加入一些自己的額外邏輯,Spring的前置、后置、環(huán)繞方法通知,都可以通過這種方式有限的模擬出來。

缺點就是,當Animal接口新增了新的方法,包裝類也必須新增方法,而且一個包裝類實際上只能對應一個接口。

 

二、繼承的代理

public class ExtendProxyTest extends Monkey{

 

   public static void main(String args[]){

   }

  

   public void eat(String food){

      System.out.println("+++warpped brfore+++");

      super.eat(food);

      System.out.println("+++warpped after+++");

     

   }

  

   public String type(){

      System.out.println("+++warpped brfore+++");

      String type=super.type();

      System.out.println("+++warpped after+++");

      return type;

   }

}

這種方式最簡單,不過不能實現(xiàn)對Animal所有子類的代理,與包裝的模式相比,大大縮小了代理范圍。

 

三、動態(tài)代理

  

/**

 * 基于reflect.Proxyreflect.InvocationHandler兩個類來完成的,使用java反射機制

 *1.

Onbject proxy=Proxy.newProxyInstance(定義代理對象的類加載器,

   要代理的目標對象的歸屬接口數(shù)組, 回調接口InvacationHandler);

 *

 *2. Onbject proxy=Proxy.newProxyInstance(定義代理對象的類加載器,

            要代理的目標對象的歸屬接口數(shù)組);

   proxy=proxClass.getConstructor(

new Class[]{InvocationHandler.class}).

newInstance(new 回調接口InvocationHandler);

          

   缺點:不能對類進行代理,只能對接口進行代理。因為生成的代理類$Proxy這個類繼承了Proxy,Java

   繼承不允許出現(xiàn)多個父類*

 */

public class DynamicProxy {

 

   public static void main(String args[]) throws {

      /*

       * 使用第一種方法來創(chuàng)建代理對象

       */

      Object proxy=Proxy.newProxyInstance(

   Monkey.class.getClassLoader(),

   Monkey.class.getInterfaces(),

         new AnimalInvocationHandler(new Monkey()));

      /*

       * 代理對象調用的時候,會調用回調的invoke方法,Method.args是調用invoke的時候傳入的

       */

      Animal animal=(Animal)proxy;

      animal.eat("橡膠");

      animal.type();

     
      /*

       第2中方式       */

   Class<?> proxClass=Proxy.getProxyClass(

Monkey.class.getClassLoader(),

 Monkey.class.getInterfaces());

 

   proxy=proxClass.getConstructor(new

         Class[]{InvocationHandler.class}).

newInstance(new AnimalInvocationHandler(

new Monkey()));

       

       animal=(Animal)proxy;

       animal.eat("香蕉");

       animal.type();

       

       Primate pre=(Primate)proxy;

       pre.think();

   }}

 

回調類:

 

/**

 * 回調類。

 *

 * InvocationHandler接口只有一個invoke需要實現(xiàn),這個方法會在目標對象的方法調用的時候被激活

 * 你可以在這里控制目標對象的方法的調用,在調用前后插入一些其他從操作

 * 比如:鑒權、日志,事務管理等。

 *

 * 后兩個參數(shù),一個是調用的方法的Method對象,另一個是方法的參數(shù),第一個參數(shù),,就是我們使用Proxy

 * 的靜態(tài)方法創(chuàng)建的動態(tài)代理的對象,也就是$Proxy實例,由于$ProxyJDK中不是靜態(tài)存在的,所以不可以把

 * Object proxy強制轉換成$Proxy類型,因為你根本就無法從Classpath中道途$Proxy。那么我們可以把proxy

 * 轉換為目標接口對象嗎?可以。因為$Proxy是實現(xiàn)了目標對象的,但是這樣的實際意義不大,因為轉換為

 * 目標對象的接口之后,你調用接口中的任何方法,都會導致invoke的調用陷入死循環(huán)而導致棧溢出。

 * 這是因為目標對象的大部分方法都被代理了,在invoke通過代理對象轉換之后的接口,調用目標對象的方法

 * 依然走的是代理對象

 *

 * 所以第一個參數(shù),一般情況下都用不到,除非想獲得代理對象$Proxy的類描述信息,它的getClass方法不會陷入死循環(huán).

 * 不過還是要注意,調用$proxy的從object上繼承的方法,比如hashCode等也會導致陷入死循環(huán),因為getClass()

 * 方法是final的,不可以被覆蓋,所以也就不會被Proxy代理。當然,因為Proxy代理的是Monkey接口,不是Monkey本身,

 * 所以即使Monkey在實現(xiàn)Animal、Primate接口的時候,把方法都變?yōu)?/span>final,也不會影響到proxy的動態(tài)代理。 *

 * *

 */

public class AnimalInvocationHandler implements InvocationHandler{

 

   private Object obj;

  

   public AnimalInvocationHandler(Animal animal){

      this.obj=animal;

   }

  

   /**

    * proxy是實際的代理對象

    */

   public Object invoke(Object proxy, Method method, Object[] args)

         throws Throwable {

      System.out.println("invoke method hefore");

      Object returnObj=method.invoke(obj, args);

      System.out.println("invoke method hefore");

     

      return returnObj;

   }

 

}

 

CGLIB

 

該類沒有實現(xiàn)接口,并且有一個final方法

public class Monkey{

 

   public void eat(String food) {

      System.out.println("the food is "+food+" !");

     

   }

  

   public final String type() {

      String type="哺乳動物";

      System.out.println(type);

      return type;

   }

 

   public void think() {

      System.out.println("思考");

     

   }

 

}

 

/**

 * CGLIB進行動態(tài)代理的編程于Proxy沒有多少不同,EnhancerCGLIB的入口,通過它

 * 創(chuàng)建代理對象,同時為代理對象分配一個Callbacl回調接口,用于執(zhí)行回調。

 *

 * 常用的是MethodInterceptor,他繼承Callback,用于執(zhí)行方法攔截。另外還有一些內置的回調處理:

 * 1.FixedValue,為提高性能,FixedValue回調對槍支某一特別方法返回固定值是有用的

 * 2.NoOp,該回調把方法調用直接委派到這個方法在父類中的實現(xiàn),相當于不處理

 * 3.LazyLoader,當時機的對象需要延遲加載時,可以使用LazyLoader回調。一旦實際對象被裝載,

 * 它將被每一個調用代理對象的方法使用

 *

 * CGLIBHibernateSpring等很多開源框架內部使用,用于完成對類的動態(tài)代理,Spring中的很多XML配置屬性的proxy-target-class

 * 默認都為false,含義就是默認不啟用對目標類的動態(tài)代理,而是對接口動態(tài)代理。某些情況下,如果相對Struts2Action或者Spring

 * MVCController進行動態(tài)代理,會發(fā)現(xiàn)默認Spring會報告找不到$ProxyXXX方法,這是因為一般我們都不會給控制層寫一個接口,

 * 而是直接在實現(xiàn)類中寫請求方法,這樣JDK自帶的Proxy是找不到這些方法的,應為他們不在借口中,此時就要設置proxy-target-class="true"

 * 引入CGLIB/ASM等庫。

 */

public class CglibMethodInterceptor implements MethodInterceptor{

 

   /**

    * 1.obj 代理對象

    * 2.被調用的方法

    * 3.方法的參數(shù)

    * 4.CGLIB提供的方法代理對象

    *

    * 一般使用最后一個參數(shù),而不是第2個,java的反射,因為CGLIB試用ASM

    * 字節(jié)碼操作,代理對象的執(zhí)行效率比反射機制更高.而且,試用method會造成死循環(huán)

    */

   public Object intercept(Object obj, Method method, Object[] args,

         MethodProxy proxy) throws Throwable {

      System.out.println("=============================");

      Object o=proxy.invokeSuper(obj, args);

      //Object o1=method.invoke(obj, args);

     

      System.out.println("++++++++++++++++++++++++++++++");

      return o;

   }

 

   public static void main(String args[])

   {

      /**

       * create方法用來創(chuàng)建代理對象

       */

      Monkey mon=(Monkey)Enhancer.create(Monkey.class,

            new CglibMethodInterceptor());

      mon.think();

      /*

       * 發(fā)現(xiàn)type方法沒有被代理,沒有輸出裝飾的信息

       * 這是因為CGLIB代理的原理是試用ASM動態(tài)生成目標對象的子類,final方法不能

       * 被子類覆蓋,所以也就不能被動態(tài)代理,這也是CGLIB的一個缺點

       */

      mon.type();

      mon.eat("xiangjiao");

     

      System.out.println("hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh");

     

      /*

       * 很多情況下,我們不是使用靜態(tài)方法,而不是Enhancer的實例去完成動態(tài)代理對象的創(chuàng)建

       * 因為試用實例,可以獲得更多的功能,比如是否使用緩存,生成策略等等.

       *

       * ,默認情況,子類會繼承父類無參的構造方法進行實例化,如果想

       * 調用其他構造器,那么用.create(argumentTypes, arguments),參數(shù)分別是構造方法的

       * 參數(shù)類型、傳遞參數(shù)

       */

      Enhancer enhancer=new Enhancer();

      enhancer.setSuperclass(Monkey.class);

      /*

       * 可以使用setCallbacks(Callback[] callbacks)方法為代理對象設置一組回調器

       * 可以配合CallbackFilter為不同方法使用不同的回調器。CallbackFilteraccept方法

       * 返回的是回調器的索引值

       */

      enhancer.setCallbacks(new Callback[]{new CglibMethodInterceptor(),NoOp.INSTANCE});

      enhancer.setCallbackFilter(new CallbackFilter() {

        

         public int accept(Method method) {

            // 方法think使用回調數(shù)組中的第二個回調器

            if(method.getName().equals("think"))

                return 1;

            else return 0;

         }

      });

      Monkey monk=(Monkey)enhancer.create();

      monk.think();

      monk.type();

      monk.eat("xiangjiao");

     

   }

  

}

 

本站僅提供存儲服務,所有內容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權內容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
面試題目(四)
面向對象設計
Java動態(tài)代理設計模式
設計模式學習心得(持續(xù)更新)
別再說 Spring AOP 默認用的是 JDK 動態(tài)代理
面向對象設計框架
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服