<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 0, comments - 77, trackbacks - 0, articles - 356
      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

    反射和代理

    Posted on 2007-09-07 15:36 semovy 閱讀(308) 評論(0)  編輯  收藏 所屬分類: JAVA基礎

    一. 關于數據庫.
    當今的數據處理大致可以分成兩大類:聯機事務處理OLTP(on-line transaction processing)、聯機分析處理OLAP(On-Line Analytical Processing)。OLTP是傳統的關系型數據庫的主要應用,主要是基本的、日常的事務處理,例如銀行交易。OLAP是數據倉庫系統的主要應用,支持復雜的分析操作,側重決策支持,并且提供直觀易懂的查詢結果。下表列出了OLTP與OLAP之間的比較。

                                           OLTP                                                              OLAP
    用戶                               操作人員,低層管理人員                               決策人員,高級管理人員
    功能                              日常操作處理                                                 分析決策
    DB 設計                        面向應用                                                        面向主題
    數據                               當前的, 最新的細節的, 二維的分立的         歷史的, 聚集的, 多維的集成的, 統一的
    存取                              讀/寫數十條記錄                                           讀上百萬條記錄
    工作單位                       簡單的事務                                                     復雜的查詢
    用戶數                         上千個                                                             上百個
    DB 大小                       100MB-GB                                                      100GB-TB

    二. Java中的類反射:
    反射就是把Java類中的各種成分映射成相應的java類.
    Reflection 是 Java 程序開發語言的特征之一,它允許運行中的 Java 程序對自身進行檢查,或者說“自審”,并能直接操作程序的內部屬性。

    1.檢測類:

    1.1 reflection的工作機制

    考慮下面這個簡單的例子,讓我們看看 reflection 是如何工作的。

    import java.lang.reflect.*;
    public class DumpMethods {
    public static void main(String args[]) {
       try {
        Class c = Class.forName(args[0]);
        Method m[] = c.getDeclaredMethods();
        for (int i = 0; i < m.length; i++)
        System.out.println(m[i].toString());
       }
       catch (Throwable e) {
        System.err.println(e);
       }
    }
    }

    按如下語句執行:

    java DumpMethods java.util.Stack

    它的結果輸出為:

    public java.lang.Object java.util.Stack.push(java.lang.Object)

    public synchronized java.lang.Object java.util.Stack.pop()

    public synchronized java.lang.Object java.util.Stack.peek()

    public boolean java.util.Stack.empty()

    public synchronized int java.util.Stack.search(java.lang.Object)

    這樣就列出了java.util.Stack 類的各方法名以及它們的限制符和返回類型。

    這個程序使用 Class.forName 載入指定的類,然后調用 getDeclaredMethods 來獲取這個類中定義了的方法列表。java.lang.reflect.Methods 是用來描述某個類中單個方法的一個類。

    1.2 Java類反射中的主要方法

    對于以下三類組件中的任何一類來說 -- 構造函數、字段和方法 -- java.lang.Class 提供四種獨立的反射調用,以不同的方式來獲得信息。調用都遵循一種標準格式。以下是用于查找構造函數的一組反射調用:

    Constructor getConstructor(Class[] params) -- 獲得使用特殊的參數類型的公共構造函數,

    Constructor[] getConstructors() -- 獲得類的所有公共構造函數

    Constructor getDeclaredConstructor(Class[] params) -- 獲得使用特定參數類型的構造函數(與接入級別無關)

    Constructor[] getDeclaredConstructors() -- 獲得類的所有構造函數(與接入級別無關)

    獲得字段信息的Class 反射調用不同于那些用于接入構造函數的調用,在參數類型數組中使用了字段名:

    Field getField(String name) -- 獲得命名的公共字段

    Field[] getFields() -- 獲得類的所有公共字段

    Field getDeclaredField(String name) -- 獲得類聲明的命名的字段

    Field[] getDeclaredFields() -- 獲得類聲明的所有字段

    用于獲得方法信息函數:

    Method getMethod(String name, Class[] params) -- 使用特定的參數類型,獲得命名的公共方法

    Method[] getMethods() -- 獲得類的所有公共方法

    Method getDeclaredMethod(String name, Class[] params) -- 使用特寫的參數類型,獲得類聲明的命名的方法

    Method[] getDeclaredMethods() -- 獲得類聲明的所有方法


    1.3開始使用 Reflection:

    用于 reflection 的類,如 Method,可以在 java.lang.relfect 包中找到。使用這些類的時候必須要遵循三個步驟:第一步是獲得你想操作的類的 java.lang.Class 對象。在運行中的 Java 程序中,用 java.lang.Class 類來描述類和接口等。

    下面就是獲得一個 Class 對象的方法之一:

    Class c = Class.forName("java.lang.String");

    這條語句得到一個 String 類的類對象。還有另一種方法,如下面的語句:

    Class c = int.class;

    或者

    Class c = Integer.TYPE;

    它們可獲得基本類型的類信息。其中后一種方法中訪問的是基本類型的封裝類 (如 Integer) 中預先定義好的 TYPE 字段。

    第二步是調用諸如 getDeclaredMethods 的方法,以取得該類中定義的所有方法的列表。

    一旦取得這個信息,就可以進行第三步了——使用 reflection API 來操作這些信息,如下面這段代碼:

    Class c = Class.forName("java.lang.String");

    Method m[] = c.getDeclaredMethods();

    System.out.println(m[0].toString());

    它將以文本方式打印出 String 中定義的第一個方法的原型。

    2.處理對象:

    如果要作一個開發工具像debugger之類的,你必須能發現filed values,以下是三個步驟:

    a.創建一個Class對象
    b.通過getField 創建一個Field對象
    c.調用Field.getXXX(Object)方法(XXX是Int,Float等,如果是對象就省略;Object是指實例).

    例如:
    import java.lang.reflect.*;
    import java.awt.*;

    class SampleGet {  
    public static void main(String[] args) {
       Rectangle r = new Rectangle(100, 325);
       printHeight(r);  
    }

    static void printHeight(Rectangle r) {
       Field heightField;
       Integer heightValue;
       Class c = r.getClass();
       try {
        heightField = c.getField("height");
        heightValue = (Integer) heightField.get(r);
        System.out.println("Height: " + heightValue.toString());
       } catch (NoSuchFieldException e) {
        System.out.println(e);
       } catch (SecurityException e) {
        System.out.println(e);
       } catch (IllegalAccessException e) {
        System.out.println(e);
       }
    }
    }

    顧名思義,反射 (reflection) 機制就像是在吳承恩所寫的西游記中所提及的「照妖鏡」,可以讓類別或對象 (object) 在執行時期「現出原形」。我們可以利用反射機制來深入了解某類(class) 的構造函數 (constructor)、方法 (method)、字段 (field),甚至可以改變字段的值、呼叫方法、建立新的對象。有了反射機制,程序員即使對所想使用的類別所知不多,也能照樣寫程序。反射機制能夠用來呼叫方法,這正是反射機制能夠取代函數指針的原因。

    以 Java 來說,java.lang.reflect.Method (以下簡稱 Method) 類別是用來表示某類別的某方法。我們可以透過 java.lang.Class (以下簡稱 Class) 類別的許多方法來取得 Method 對象。Method 類別提供 invoke() 方法,透過 invoke(),此 Method 對象所表示的方法可以被呼叫,所有的參數則是被組織成一個數組,以方便傳入 invoke()。

    舉個例子,下面是一個名為 Invoke 的程序,它會將命令列的 Java 類別名稱和要呼叫的方法名稱作為參數。為了簡單起見,我假定此方法是靜態的,且沒有參數:

    import java.lang.reflect.*;
    class Invoke {        
    public static void main(String[] args ) {               
       try {                       
        Class c = Class.forName( args[0] );                       
        Method m = c.getMethod( args[1], new Class [] { } );                       
        Object ret = m.invoke( null, null );                       
        System.out.println(args[0] + "." + args[1] +"() = " + ret );               
       } catch ( ClassNotFoundException ex ) {                       
        System.out.println("找不到此類別");               
       } catch (NoSuchMethodException ex ) {                       
        System.out.println("此方法不存在");               
       } catch (IllegalAccessException ex ) {                       
        System.out.println("沒有權限調用此方法");               
       } catch (InvocationTargetException ex ) {                       
        System.out.println("調用此方法時發生下列例外:\n" + ex.getTargetException() );               
       }        
    }
    }
    我們可以執行 Invoke 來取得系統的時間:

    java Invoke java.lang.System CurrentTimeMillis執行的結果如下所示:

    java.lang.System.currentTimeMillis() = 1049551169474我們的第一步就是用名稱去尋找指定的 Class。我們用類別名稱 (命令列的第一個參數) 去呼叫 forName() 方法,然后用方法名稱 (命令列的第二個參數) 去取得方法。getMethod() 方法有兩個參數:第一個是方法名稱 (命令列的第二個參數),第二個是 Class 對象的數組,這個陣例指明了方法的 signature (任何方法都可能會被多載,所以必須指定 signature 來分辨。) 因為我們的簡單程序只呼叫沒有參數的方法,我們建立一個 Class 對象的匿名空數組。如果我們想要呼叫有參數的方法,我們可以傳遞一個類別數組,數組的內容是各個類別的型態,依順序排列。

    一旦我們有了 Method 對象,就呼叫它的 invoke() 方法,這會造成我們的目標方法被調用,并且將結果以 Object 對象傳回。如果要對此對象做其它額外的事,你必須將它轉型為更精確的型態。

    invoke() 方法的第一個參數就是我們想要呼叫目標方法的對象,如果該方法是靜態的,就沒有對象,所以我們把第一個參數設為 null,這就是我們范例中的情形。第二個參數是要傳給目標方法作為參數的對象數組,它們的型態要符合呼叫 getMethod() 方法中所指定的型態。因為我們呼叫的方法沒有參數,所以我們傳遞 null 作為 invoke() 的第二個參數。


    import   java.lang.reflect.Constructor;
    import   java.lang.reflect.Field;
    import   java.lang.reflect.Method;
    import   java.lang.reflect.Modifier;
    import   java.util.HashMap;

    public    class   TestRef    {
          public    static    void   main(String[] args)   throws   Exception   {
             TestRef testRef   =    new   TestRef();
             Class clazz   =   TestRef. class ;
             System.out.println( " getPackage() =   "    +   clazz.getPackage().getName());
             //   getModifiers()的返回值可以包含類的種類信息。比如是否為public,abstract,static
             int   mod   =   clazz.getModifiers();
             System.out.println( " Modifier.isAbstract(mod) =   " + Modifier.isAbstract(mod));
             System.out.println( " getName() =   " + clazz.getName());
             System.out.println( " getSuperclass() =   " + clazz.getSuperclass().getName());
             System.out.println( " getInterfaces() =   " + clazz.getInterfaces()); // 實現了哪些Interface
             System.out.println( " clazz.getDeclaredClasses() =   " + clazz.getDeclaredClasses()); // 包含哪些內部類
             System.out.println( " getDeclaringClass() =   " + clazz.getDeclaringClass());
             // 如果clazz是inner class 那么返回其outer class
             
             System.out.println( " ---------- " );
             Constructor[] constructor   =   clazz.getDeclaredConstructors(); // 返回一組構造函數 Constructor[]
                if   (constructor   !=    null )   {
                  for   ( int   i   =    0 ; i   <   constructor.length; i ++ )    {
                     System.out.println(constructor[i].getName());
                 }
             }
            
             System.out.println( " ---------- " );
             Method[] method   =   clazz.getDeclaredMethods();   //   Method[]
                if   (method   !=    null )   {
                  for   ( int   i   =    0 ; i   <   method.length; i ++ )    {
                     System.out.println(method[i].getName());
                 }
             }
            
             System.out.println( " ---------- " );
             Field[] field   =   clazz.getDeclaredFields();   //   Field[]
                if   (field   !=    null )   {
                  for   ( int   i   =    0 ; i   <   field.length; i ++ )    {
                     System.out.println(field[i].getName());
                     System.out.println(field[i].getType().getName());
                     System.out.println(field[i].get(testRef));
                 }
             }
            
             //   動態生成instance(無參數)
             Class clz   =   Class.forName( " reflection.TestRef " );
             Object obj   =   clz.newInstance();
             System.out.println(((TestRef)obj).getStr());
            
             //   動態生成instance(有參數)
              Class[] params   =    new   Class[]   {String. class ,   int . class ,   double . class } ;
             Constructor construct   =   clz.getConstructor(params);
             //   JDK1.5的情況下可以直接用{"haha",999,100.01}作為參數         
              Object obj2   =   construct.newInstance(new Object[]{"haha",new Integer( 999 ),   new   Double( 100.01 )} );
             System.out.println(((TestRef)obj2).getStr());
            
             //   動態調用method(public method)
              Class[] params2   =    new   Class[]   {String. class } ;
             Method methods   =   clz.getMethod( " setStr " , params2);
             methods.invoke(testRef,   new   Object[]   { " invoke method " } );
             System.out.println(testRef.getStr());
            
             //   動態改變field內容(public field)
             Field fields   =   clz.getField( " str " );
             fields.set(testRef,   " set field's value " );
             System.out.println(testRef.getStr());
            
         }

          public   TestRef()   {
             System.out.println( " --- complete TestRef() --- " );
         }
        
         public   TestRef(String str,   int   i,   double   d)   {
              this .str   =   str;
              this .i   =   i;
              this .d   =   d;
             System.out.println( " --- complete TestRef(String str, int i, double d) --- " );
         }
        
         public   String str   =    " I'm a string " ;

         int   i   =    1 ;

         double   d   =    3.14 ;

         HashMap map   =    new   HashMap();

          public    double   getD()    {
              return   d;
         }

           public    void   setD( double   d)    {
              this .d   =   d;
         }

           public    int   getI()    {
              return   i;
         }

           public    void   setI( int   i)    {
              this .i   =   i;
         }

           public   HashMap getMap()    {
              return   map;
         }

           public    void   setMap(HashMap map)    {
              this .map   =   map;
         }

           public   String getStr()    {
              return   str;
         }

           public    void   setStr(String str)    {
              this .str   =   str;
         }
    }

    三. 代理(Proxy)
    1.
    我們直接從代碼入手吧,我們可以使用一個動態代理類(Proxy),通過攔截一個對象的行為并添加我們需要的功能來完成。Java中的java.lang.reflect.Proxy類和java.lang.reflect.InvocationHandler接口為我們實現動態代理類提供了一個方案,但是該方案針對的對象要實現某些接口;如果針對的目的是類的話,cglib為我們提供了另外一個實現方案。等下會說明兩者的區別。
    一、接口的實現方案:
    1)首先編寫我們的業務接口(StudentInfoService.java):
    public interface StudentInfoService{
    void findInfo(String studentName);
    }
          及其實現類(StudentInfoServiceImpl.java):
    public class StudentInfoServiceImpl implements StudentInfoService{
    public void findInfo(String name){
       System.out.println("你目前輸入的名字是:"+name);
    }
    }
    2)現在我們需要一個日志功能,在findInfo行為之前執行并記錄其行為,那么我們就首先要攔截該行為。在實際執行的過程中用一個代理類來替我們完成。Java中為我們提供了實現動態代理類的方案:

    1'處理攔截目的的類(MyHandler.java)
    import org.apache.log4j.Logger;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
    import java.lang.reflect.Method;

    public class MyHandler implements InvocationHandler{
    private Object proxyObj;
    private static Logger log=Logger.getLogger(MyHandler.class);

    public Object bind(Object obj){
       this.proxyObj=obj;
       return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this);
    }

    public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
       Object result=null;
       try{
        //請在這里插入代碼,在方法前調用
        log.info("調用log日志方法"+method.getName());
        result=method.invoke(proxyObj,args); //原方法
        //請在這里插入代碼,方法后調用
       }catch(Exception e){
        e.printStackTrace();
       }
       return result;
    }
    }
    2'我們實現一個工廠,為了方便我們使用該攔截類(AOPFactory.java):
    public class AOPFactory{
    private static Object getClassInstance(String clzName){
       Object obj=null;
       try{
        Class cls=Class.forName(clzName);
        obj=(Object)cls.newInstance();
       }catch(ClassNotFoundException cnfe){
        System.out.println("ClassNotFoundException:"+cnfe.getMessage());
       }catch(Exception e){
        e.printStackTrace();
       }
       return obj;
    }

    public static Object getAOPProxyedObject(String clzName){
       Object proxy=null;
       MyHandler handler=new MyHandler();
       Object obj=getClassInstance(clzName);
       if(obj!=null) {
        proxy=handler.bind(obj);
       }else{
        System.out.println("Can't get the proxyobj");
        //throw
       }
       return proxy;
    }
    }

    3)基本的攔截與其工廠我們都實現了,現在測試(ClientTest.java):
    public class ClientTest{
    public static void main(String[] args){
       StudentInfoService studentInfo=(StudentInfoService)AOPFactory.getAOPProxyedObject("StudentInfoServiceImpl");
       studentInfo.findInfo("阿飛");
    }
    }
    輸出結果(看你的log4j設置):
    [INFO]調用log日志方法findInfo
    你目前輸入的名字是:阿飛
          這樣我們需要的效果就出來了,業務處理自己在進行,但是我們實現了日志功能

    2.再看一個例子:
      假設系統由一系列的BusinessObject所完成業務邏輯功能,系統要求在每一次業務邏輯處理時要做日志記錄。這里我們略去具體的業務邏輯代碼。

    public interface BusinessInterface {
     public void processBusiness();
    }

    public class BusinessObject implements BusinessInterface {
     private Logger logger = Logger.getLogger(this.getClass().getName());
     public void processBusiness(){
      try {
       logger.info("start to processing...");
       //business logic here.
       System.out.println(“here is business logic”);
       logger.info("end processing...");
      } catch (Exception e){
       logger.info("exception happends...");
       //exception handling
      }
     }
    }

      這里處理商業邏輯的代碼和日志記錄代碼混合在一起,這給日后的維護帶來一定的困難,并且也會造成大量的代碼重復。完全相同的log代碼將出現在系統的每一個BusinessObject中。

    按照AOP的思想,我們應該把日志記錄代碼分離出來。要將這些代碼分離就涉及到一個問題,我們必須知道商業邏輯代碼何時被調用,這樣我們好插入日志記錄代碼。一般來說要截獲一個方法,我們可以采用回調方法或者動態代理。動態代理一般要更加靈活一些,目前多數的AOP Framework也大都采用了動態代理來實現。這里我們也采用動態代理作為例子。
    JDK1.2以后提供了動態代理的支持,程序員通過實現java.lang.reflect.InvocationHandler接口提供一個執行處理器,然后通過java.lang.reflect.Proxy得到一個代理對象,通過這個代理對象來執行商業方法,在商業方法被調用的同時,執行處理器會被自動調用。

      有了JDK的這種支持,我們所要做的僅僅是提供一個日志處理器。

    public class LogHandler implements InvocationHandler {

     private Logger logger = Logger.getLogger(this.getClass().getName());
      private Object delegate;
      public LogHandler(Object delegate){
       this.delegate = delegate;
      }

     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      Object o = null;
      try {
       logger.info("method stats..." + method);
       o = method.invoke(delegate,args);
       logger.info("method ends..." + method);
      } catch (Exception e){
       logger.info("Exception happends...");
       //excetpion handling.
      }
      return o;
     }
    }

      現在我們可以把BusinessObject里面的所有日志處理代碼全部去掉了。

    public class BusinessObject implements BusinessInterface {

     private Logger logger = Logger.getLogger(this.getClass().getName());
     public void processBusiness(){
      //business processing
      System.out.println(“here is business logic”);
     }
    }

      客戶端調用商業方法的代碼如下:

    BusinessInterface businessImp = new BusinessObject();

    InvocationHandler handler = new LogHandler(businessImp);

    BusinessInterface proxy = (BusinessInterface) Proxy.newProxyInstance(
     businessImp.getClass().getClassLoader(),
     businessImp.getClass().getInterfaces(),
     handler);

    proxy.processBusiness();

      程序輸出如下:

    INFO: method stats...
    here is business logic
    INFO: method ends...

      至此我們的第一次小嘗試算是完成了。可以看到,采用AOP之后,日志記錄和業務邏輯代碼完全分開了,以后要改變日志記錄的話只需要修改日志記錄處理器就行了,而業務對象本身(BusinessObject)無需做任何修改。并且這個日志記錄不會造成重復代碼了,所有的商業處理對象都可以重用這個日志處理器。

    主站蜘蛛池模板: 亚洲性线免费观看视频成熟| 国产精品成人免费视频网站京东| 国产精品亚洲不卡一区二区三区 | 免费无遮挡无码视频在线观看 | 美女羞羞喷液视频免费| 无码视频免费一区二三区| 亚洲中文字幕日本无线码| 国产va免费精品观看精品 | 亚洲色大成网站WWW久久九九| 亚洲一区二区三区在线观看精品中文 | 无码国产精品一区二区免费16| 中文字幕免费视频| 亚洲日韩中文字幕| 日本妇人成熟免费中文字幕| 亚洲中文字幕人成乱码| 麻豆国产VA免费精品高清在线| 亚洲国产三级在线观看| 97在线免费观看视频| 亚洲AV无码成人精品区蜜桃| 100部毛片免费全部播放完整| 国产一级特黄高清免费大片| 深夜免费在线视频| 亚洲最大AV网站在线观看| 久久这里只精品国产免费10| 亚洲国产日产无码精品| 国产免费私拍一区二区三区| 国产在线观a免费观看| 亚洲欧洲国产综合| 四虎在线播放免费永久视频 | 亚洲欧洲日产国码高潮αv| 中文在线观看国语高清免费| 久久久久久久亚洲Av无码| 国内一级一级毛片a免费| 曰批免费视频播放在线看片二 | 99久在线国内在线播放免费观看| 国产成人3p视频免费观看| sss在线观看免费高清| 亚洲国产超清无码专区| 日韩免费观看的一级毛片| 成全高清在线观看免费| 在线综合亚洲中文精品|