Java反射與代理

Java反射機制與動態代理,使得Java更增強大,Spring核心概念IoCAOP就是經過反射機制與動態代理實現的。java

1       Java反射

示例:程序員

User user = new User();
user.setTime5Flag("test");
 
Class<?> cls = Class.forName("com.test.User");
//接口必須public,不管是否在本類內部使用!或者使用cls.getDeclaredMethod(),或者遍歷修改可訪問性
Method method = cls.getMethod("getTime5Flag");
String res1 = (String) method.invoke(user);
System.out.println(res1);
//涉及到基本類型如int,則使用int.class!Integer.class!=int.class!
method = cls.getMethod("setTime5Flag", String.class); 
method.invoke(user, "Rollen");
method = cls.getMethod("getTime5Flag");
String res2 = (String) method.invoke(user);
System.out.println(res2);

 

經過一個對象得到完整的包名和類名:編程

user.getClass().getName();//全路徑類名
user.getClass().getSimpleName();//無包名的類名

 

獲取class:
Class.forName("com.test.User");
com.test.User.class;
user.getClass();

 

經過class實例化一個對象
User user = (User) cls.newInstance();//必須有無參構造函數

 

取得所有構造函數
Constructor<?> cons[]=cls.getConstructors(); //按聲明順序返回
cons[0].newInstance();//無顯示聲明,則有默認構造函數

 

取得一個類所實現的全部interface 
Class<?> intes[] = cls.getInterfaces();

 

取得父類
cls.getSuperClass();

 

取得修飾符
int mo = cls.getModifiers();
int mo = cons[0].getModifiers();
int mo = method.getModifiers();
Modifier.toString(mo);

 

獲取方法參數
method.getParametors();
cons[0].getParametors();

 

獲取方法參數類型
method.getParametorTypes();
cons[0].getParametorTypes();

 

獲取方法聲明拋出的全部異常類型
method.getExceptionTypes();

 

獲取本類聲明的所有屬性
Field[] field = cls.getDeclaredFields(); //包括private
field[0].getModifiers();
field[0].getType();

 

獲取本類的所有公開屬性,包括父類聲明、接口聲明、本類聲明的全部public屬性segmentfault

cls.getFields();

 

設置指定屬性可訪問設計模式

field.setAccessible(true);
field.set(obj,’ces’);
field.get(obj);

 

* getFields()與getDeclaredFields()區別:getFields()只能訪問類中聲明爲公有的字段,私有的字段它沒法訪問,能訪問從其它類繼承來的公有字段;getDeclaredFields()能訪問類中全部的字段,與public,private,protect無關,但不能訪問從其它類繼承來的字段數組

* getMethods()與getDeclaredMethods()區別:getMethods()只能訪問類中聲明爲公有的方法,私有的方法它沒法訪問,能訪問從其它類繼承來的公有方法;getDeclaredMethods()能訪問類中全部的字段,與public,private,protect無關,不能訪問從其它類繼承來的方法ide

* getConstructors()與getDeclaredConstructors()區別:getConstructors()只能訪問類中聲明爲public的構造函數;getDeclaredConstructors()能訪問類中全部的構造函數,與public,private,protect無關函數

 

經過反射獲取並修改數組的信息
int[] temp={1,2,3,4,5};
Class<?> demo = temp.getClass().getComponentType();
System.out.println("數組類型: "+demo.getName());//int
System.out.println("數組長度: "+Array.getLength(temp));//5
System.out.println("數組的第一個元素: "+Array.get(temp, 0));//1
Array.set(temp, 0, 100);
System.out.println("修改以後數組第一個元素爲: "+Array.get(temp, 0));//100

 

獲取數組類型
cls.getComponentType();

 

判斷是不是數組類型
cls.isArray();

 

2       Java代理

代理模式是經常使用的Java設計模式,它的特徵是代理類與委託類有一樣的接口,代理類主要負責爲委託類預處理消息、過濾消息、把消息轉發給委託類,以及過後處理消息等。代理類與委託類之間一般會存在關聯關係,一個代理類的對象與一個委託類的對象關聯,代理類的對象自己並不真正實現服務,而是經過調用委託類的對象的相關方法,來提供特定的服務。工具

按照代理的建立時期,代理類能夠分爲2種。測試

  • 靜態代理:由程序員建立或特定工具自動生成源代碼,再對其編譯。在程序運行前,代理類的.class文件就已經存在了。
  • 動態代理:在程序運行時,由Java反射機制動態生成字節碼。

2.1   靜態代理

public interface Count { 
    public void queryCount();
}
public class CountImpl implements Count {
    public void queryCount() { 
        System.out.println("查看帳戶方法...");
    }
}
//代理類
public class CountProxy implements Count { 
    private CountImpl countImpl;   
    public CountProxy(CountImpl countImpl) { 
        this.countImpl = countImpl; 
    }   
    @Override 
    public void queryCount() { 
        System.out.println("事務處理以前");           
        countImpl.queryCount(); // 調用委託類的方法;
        System.out.println("事務處理以後"); 
    }
} 
//測試類
public class TestCount { 
    public static void main(String[] args) { 
        CountImpl countImpl = new CountImpl(); 
        CountProxy countProxy = new CountProxy(countImpl); 
        countProxy.queryCount();   
    } 
}

 

觀察代碼能夠發現每個代理類只能爲一個接口服務,這樣一來程序開發中必然會產生過多的代理,並且,全部的代理操做除了調用的方法不同以外,其餘的操做都同樣,則此時確定是重複代碼。解決這一問題最好的作法是能夠經過一個代理類完成所有的代理功能,那麼此時就必須使用動態代理完成。

 

2.2   動態代理

動態代理類的字節碼在程序運行時由Java反射機制動態生成,無需程序員手工編寫它的源代碼。動態代理類不只簡化了編程工做,並且提升了軟件系統的可擴展性,由於Java 反射機制能夠生成任意類型的動態代理類。

2.2.1  JDK動態代理

java.lang.reflect 包中的Proxy類和InvocationHandler 接口提供了生成動態代理類的能力。

InvocationHandler接口: 

public interface InvocationHandler { 
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable; 

參數說明: 

Object proxy:指被代理的對象。 
Method method:要調用的方法 
Object[] args:方法調用時所須要的參數 

能夠將InvocationHandler接口的子類想象成一個代理的最終操做類,替換掉ProxySubject。 

Proxy類: 

Proxy類是專門完成代理的操做類,能夠經過此類爲一個或多個接口動態地生成實現類,此類提供了以下的操做方法: 

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException 

參數說明: 

ClassLoader loader:類加載器 
Class<?>[] interfaces:獲得所有的接口 
InvocationHandler h:獲得InvocationHandler接口的子類實例 

 

若是想要完成動態代理,首先須要定義一個InvocationHandler接口的子類,以完成代理的具體操做。

interface Subject {
    public String say(String name, int age);
}
class RealSubject implements Subject {
    @Override
    public String say(String name, int age) {
        return name + "  " + age;
    }
}
//JDK動態代理類
class MyInvocationHandler implements InvocationHandler {
    private Object target = null;
    //綁定委託對象並返回一個代理類
    public Object bind(Object target) {
        this. target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
          target.getClass().getInterfaces(),
this); //要綁定接口(cglib彌補了這一點) } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(「before method!」); Object temp = method.invoke(target, args); System.out.println(「after method!」); return temp; } } class hello { public static void main(String[] args) { MyInvocationHandler demo = new MyInvocationHandler(); Subject sub = (Subject) demo.bind(new RealSubject()); String info = sub.say("Rollen", 20); System.out.println(info); } }

 

可是,JDK的動態代理依靠接口實現,若是有些類並無實現接口,則不能使用JDK代理,這就要使用cglib動態代理了。 
 

2.2.2  CGLIB動態代理

JDK的動態代理機制只能代理實現了接口的類,而未實現接口的類就不能實現JDK的動態代理。

cglib是針對類來實現代理的,它的原理是對指定的目標類生成一個子類,並覆蓋其中方法實現加強,但由於採用的是繼承,因此不能對final修飾的類進行代理。 

public interface BookFacade { 
    public void addBook(); 
} 
public class BookFacadeImpl1 { 
    public void addBook() { 
        System.out.println("增長圖書的普通方法..."); 
    } 
} 
 
import java.lang.reflect.Method;   
import net.sf.cglib.proxy.Enhancer; 
import net.sf.cglib.proxy.MethodInterceptor; 
import net.sf.cglib.proxy.MethodProxy; 
//cglib動態代理類
public class BookFacadeCglib implements MethodInterceptor { 
    private Object target;    
    //綁定委託對象並返回一個代理類
    public Object getInstance(Object target) { 
        this.target = target; 
        Enhancer enhancer = new Enhancer(); 
        enhancer.setSuperclass(this.target.getClass()); 
        // 回調方法 
        enhancer.setCallback(this); 
        // 建立代理對象 
        return enhancer.create(); 
    }    
    @Override 
    // 回調方法 
    public Object intercept(Object obj, Method method, Object[] args, 
            MethodProxy proxy) throws Throwable { 
        System.out.println("事物開始"); 
        Object temp = proxy.invokeSuper(obj, args); 
        System.out.println("事物結束"); 
        return temp;   
    } 
} 
public class TestCglib {
    public static void main(String[] args) { 
        BookFacadeCglib cglib = new BookFacadeCglib(); 
        BookFacadeImpl1 bookCglib = (BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1()); 
        bookCglib.addBook(); 
    } 
}

 

參考:
1.https://segmentfault.com/a/1190000004326040
2.http://blog.csdn.net/hintcnuie/article/details/10954631
相關文章
相關標籤/搜索