您好,登錄后才能下訂單哦!
如何探討Java代理模式與反射機制的實際應用,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。
Java提供了一套機制來動態執行方法和構造方法,以及數組操作等,這套機制就叫反射。而代理模式是為其他對象提供一種代理以控制對這個對象的訪問,讓我們的目標類和代理類實現同一接口,在代理類中調用目標類對象的方法。
反射機制是如今很多Java流行框架的實現基礎,其中包括Spring、Hibernate等。如果我們將反射機制加入到Java的代理模式中,就可以實現一個公共的代理類,省去我們不少功夫。
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * 方法代理類 * @author rongxinhua * */ public class MethodProxy { private Class clazz; //對象所屬的類 private Object target; //目標對象 private Method method; //目標方法 private Object[] params; //參數數組 @SuppressWarnings("unchecked") public MethodProxy(Object target, String methodName, Object ... params) { rebindTarget(target, methodName, params); //設置目標對象與方法 } /** * 重新設置目標對象與方法 * @param target * @param methodName * @param params */ public void rebindTarget(Object target, String methodName, Object ... params) { this.target = target; this.clazz = target.getClass(); rebindMethod(methodName, params); //設置目標方法 } /** * 重新設置目標方法 * @param methodName * @param params */ public void rebindMethod(String methodName, Object ...params) { this.params = params; int paramLength = params.length; Class[] paramTypes = new Class[paramLength]; for(int i = 0 ; i < paramLength ; i ++ ) { paramTypes[i] = params[i].getClass(); } try { this.method = clazz.getMethod(methodName, paramTypes); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } } /** * 動態調用已綁定的方法 */ public void doMethod() { try { this.method.invoke(target, params); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } } import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * 方法代理類 * @author rongxinhua * */ public class MethodProxy { private Class clazz; //對象所屬的類 private Object target; //目標對象 private Method method; //目標方法 private Object[] params; //參數數組 @SuppressWarnings("unchecked") public MethodProxy(Object target, String methodName, Object ... params) { rebindTarget(target, methodName, params); //設置目標對象與方法 } /** * 重新設置目標對象與方法 * @param target * @param methodName * @param params */ public void rebindTarget(Object target, String methodName, Object ... params) { this.target = target; this.clazz = target.getClass(); rebindMethod(methodName, params); //設置目標方法 } /** * 重新設置目標方法 * @param methodName * @param params */ public void rebindMethod(String methodName, Object ...params) { this.params = params; int paramLength = params.length; Class[] paramTypes = new Class[paramLength]; for(int i = 0 ; i < paramLength ; i ++ ) { paramTypes[i] = params[i].getClass(); } try { this.method = clazz.getMethod(methodName, paramTypes); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } } /** * 動態調用已綁定的方法 */ public void doMethod() { try { this.method.invoke(target, params); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } } 這樣就可以實現動態地調用某個對象的某個方法了,寫個測試代碼如下: public class Manager { public void say() { System.out.println("Nobody say nothing"); } public void love(String boy, String girl) { System.out.println(boy + " love " + girl); } } public class Manager { public void say() { System.out.println("Nobody say nothing"); } public void love(String boy, String girl) { System.out.println(boy + " love " + girl); } }
我們通過代理類來調用Manager類中的say()和love()方法,測試代碼如下:
Manager man = new Manager(); //目標對象 MethodProxy proxy = new MethodProxy(man, "say"); //方法代理對象 proxy.doMethod(); //調用被代理的方法 proxy.rebindMethod("love", "Tom", "Marry"); //重新綁定方法 proxy.doMethod(); //調用被代理的方法 Manager man = new Manager(); //目標對象 MethodProxy proxy = new MethodProxy(man, "say"); //方法代理對象 proxy.doMethod(); //調用被代理的方法 proxy.rebindMethod("love", "Tom", "Marry"); //重新綁定方法 proxy.doMethod(); //調用被代理的方法
這樣就實現了動態代理調用對象的方法,上面代碼輸出結果就不貼出來了。如果要設置前置通知和后置通知等功能,也很容易實現,只需在“proxy.doMethod()”代碼處的前面和后面設置即行。擴展應用:我們在上面的MethodProxy類中加入以下方法:
/** * 獲取方法上的注解 * @param anClazz 注解類 * @return */ public Annotation getAnnotation(Class anClazz) { return this.method.getAnnotation(anClazz); } /** * 獲取方法上的注解 * @param anClazz 注解類 * @return */ public Annotation getAnnotation(Class anClazz) { return this.method.getAnnotation(anClazz); }
這個方法用來讀取方法上的注解(Annotation),有什么用呢?我們寫一個注解來測試下。
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @interface Low { int boyAge(); int girlAge(); } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @interface Low { int boyAge(); int girlAge(); }
我們要引進Annotation相關的類:
import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;
我們另外寫一個測試用的業務類:
public class LoveManager { @Low(boyAge=12, girlAge=10) public void beAbleToLove(Person boy, Person girl) { System.out.println(boy.getName() + " is able to love " + girl.getName()); } } public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } //getter方法略 } public class LoveManager { @Low(boyAge=12, girlAge=10) public void beAbleToLove(Person boy, Person girl) { System.out.println(boy.getName() + " is able to love " + girl.getName()); } } public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } //getter方法略 }
接寫上例中的proxy對象測試代碼:
LoveManager loveManager = new LoveManager(); Person boy = new Person("Tom", 13); Person girl = new Person("Marry", 10); proxy.rebindTarget(loveManager, "beAbleToLove", boy, girl); //重新綁定對象和方法 Low low = (Low)proxy.getAnnotation(Low.class); if(boy.getAge() < low.boyAge()) { System.out.println(boy.getName() + "還不到法定年齡,不能談戀愛!"); } else if(girl.getAge() < low.girlAge()) { System.out.println(girl.getName() + "還不到法定年齡,不能談戀愛!"); } else { proxy.doMethod(); } LoveManager loveManager = new LoveManager(); Person boy = new Person("Tom", 13); Person girl = new Person("Marry", 10); proxy.rebindTarget(loveManager, "beAbleToLove", boy, girl); //重新綁定對象和方法 Low low = (Low)proxy.getAnnotation(Low.class); if(boy.getAge() < low.boyAge()) { System.out.println(boy.getName() + "還不到法定年齡,不能談戀愛!"); } else if(girl.getAge() < low.girlAge()) { System.out.println(girl.getName() + "還不到法定年齡,不能談戀愛!"); } else { proxy.doMethod(); }
這就實現了,通過Java的反射機制來讀取Annotation的值,并根據Annotation的值,來處理業務數據有效性的判斷,或者面向切面動態地注入對象,或者作日志、攔截器等等。這種用法在所多框架中都常常看到, 我們在開發自己的Java組件時,不妨也采用一下吧!
看完上述內容,你們掌握如何探討Java代理模式與反射機制的實際應用的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。