淺談Java反射與代理
Java反射機(jī)制與動(dòng)態(tài)代理,使得Java更加強(qiáng)大,Spring核心概念I(lǐng)oC、AOP就是通過反射機(jī)制與動(dòng)態(tài)代理實(shí)現(xiàn)的。
1 Java反射
示例:
User user = new User(); user.setTime5Flag("test"); Class<?> cls = Class.forName("com.test.User"); //接口必須public,無論是否在本類內(nèi)部使用!或者使用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);
通過一個(gè)對(duì)象獲得完整的包名和類名:
user.getClass().getName();//全路徑類名 user.getClass().getSimpleName();//無包名的類名
獲取class:
Class.forName("com.test.User"); com.test.User.class; user.getClass();
User user = (User) cls.newInstance();//必須有無參構(gòu)造函數(shù)
Constructor<?> cons[]=cls.getConstructors(); //按聲明順序返回 cons[0].newInstance();//無顯示聲明,則有默認(rèn)構(gòu)造函數(shù)
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屬性
cls.getFields();
設(shè)置指定屬性可訪問
field.setAccessible(true); field.set(obj,'ces'); field.get(obj);
* getFields()與getDeclaredFields()區(qū)別:getFields()只能訪問類中聲明為公有的字段,私有的字段它無法訪問,能訪問從其它類繼承來的公有字段;getDeclaredFields()能訪問類中所有的字段,與public,private,protect無關(guān),但不能訪問從其它類繼承來的字段
* getMethods()與getDeclaredMethods()區(qū)別:getMethods()只能訪問類中聲明為公有的方法,私有的方法它無法訪問,能訪問從其它類繼承來的公有方法;getDeclaredMethods()能訪問類中所有的字段,與public,private,protect無關(guān),不能訪問從其它類繼承來的方法
* getConstructors()與getDeclaredConstructors()區(qū)別:getConstructors()只能訪問類中聲明為public的構(gòu)造函數(shù);getDeclaredConstructors()能訪問類中所有的構(gòu)造函數(shù),與public,private,protect無關(guān)
通過反射獲取并修改數(shù)組的信息
int[] temp={1,2,3,4,5}; Class<?> demo = temp.getClass().getComponentType(); System.out.println("數(shù)組類型: "+demo.getName());//int System.out.println("數(shù)組長(zhǎng)度: "+Array.getLength(temp));//5 System.out.println("數(shù)組的第一個(gè)元素: "+Array.get(temp, 0));//1 Array.set(temp, 0, 100); System.out.println("修改之后數(shù)組第一個(gè)元素為: "+Array.get(temp, 0));//100
cls.getComponentType();
cls.isArray();
2 Java代理
代理模式是常用的Java設(shè)計(jì)模式,它的特征是代理類與委托類有同樣的接口,代理類主要負(fù)責(zé)為委托類預(yù)處理消息、過濾消息、把消息轉(zhuǎn)發(fā)給委托類,以及事后處理消息等。代理類與委托類之間通常會(huì)存在關(guān)聯(lián)關(guān)系,一個(gè)代理類的對(duì)象與一個(gè)委托類的對(duì)象關(guān)聯(lián),代理類的對(duì)象本身并不真正實(shí)現(xiàn)服務(wù),而是通過調(diào)用委托類的對(duì)象的相關(guān)方法,來提供特定的服務(wù)。
按照代理的創(chuàng)建時(shí)期,代理類可以分為2種。
•靜態(tài)代理:由程序員創(chuàng)建或特定工具自動(dòng)生成源代碼,再對(duì)其編譯。在程序運(yùn)行前,代理類的.class文件就已經(jīng)存在了。
•動(dòng)態(tài)代理:在程序運(yùn)行時(shí),由Java反射機(jī)制動(dòng)態(tài)生成字節(jié)碼。
2.1 靜態(tài)代理
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("事務(wù)處理之前"); countImpl.queryCount(); // 調(diào)用委托類的方法; System.out.println("事務(wù)處理之后"); } } //測(cè)試類 public class TestCount { public static void main(String[] args) { CountImpl countImpl = new CountImpl(); CountProxy countProxy = new CountProxy(countImpl); countProxy.queryCount(); } }
觀察代碼可以發(fā)現(xiàn)每一個(gè)代理類只能為一個(gè)接口服務(wù),這樣一來程序開發(fā)中必然會(huì)產(chǎn)生過多的代理,而且,所有的代理操作除了調(diào)用的方法不一樣之外,其他的操作都一樣,則此時(shí)肯定是重復(fù)代碼。解決這一問題最好的做法是可以通過一個(gè)代理類完成全部的代理功能,那么此時(shí)就必須使用動(dòng)態(tài)代理完成。
2.2 動(dòng)態(tài)代理
動(dòng)態(tài)代理類的字節(jié)碼在程序運(yùn)行時(shí)由Java反射機(jī)制動(dòng)態(tài)生成,無需程序員手工編寫它的源代碼。動(dòng)態(tài)代理類不僅簡(jiǎn)化了編程工作,而且提高了軟件系統(tǒng)的可擴(kuò)展性,因?yàn)镴ava 反射機(jī)制可以生成任意類型的動(dòng)態(tài)代理類。
2.2.1 JDK動(dòng)態(tài)代理
java.lang.reflect 包中的Proxy類和InvocationHandler 接口提供了生成動(dòng)態(tài)代理類的能力。
InvocationHandler接口:
public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}
參數(shù)說明:
Object proxy:指被代理的對(duì)象。
Method method:要調(diào)用的方法
Object[] args:方法調(diào)用時(shí)所需要的參數(shù)
可以將InvocationHandler接口的子類想象成一個(gè)代理的最終操作類,替換掉ProxySubject。
Proxy類:
Proxy類是專門完成代理的操作類,可以通過此類為一個(gè)或多個(gè)接口動(dòng)態(tài)地生成實(shí)現(xiàn)類,此類提供了如下的操作方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
參數(shù)說明:
ClassLoader loader:類加載器
Class<?>[] interfaces:得到全部的接口
InvocationHandler h:得到InvocationHandler接口的子類實(shí)例
如果想要完成動(dòng)態(tài)代理,首先需要定義一個(gè)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動(dòng)態(tài)代理類 class MyInvocationHandler implements InvocationHandler { private Object target = null; //綁定委托對(duì)象并返回一個(gè)代理類 public Object bind(Object target) { this. target = target; return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); //要綁定接口(cglib彌補(bǔ)了這一點(diǎn)) } @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的動(dòng)態(tài)代理依靠接口實(shí)現(xiàn),如果有些類并沒有實(shí)現(xiàn)接口,則不能使用JDK代理,這就要使用cglib動(dòng)態(tài)代理了。
2.2.2 CGLIB動(dòng)態(tài)代理
JDK的動(dòng)態(tài)代理機(jī)制只能代理實(shí)現(xiàn)了接口的類,而未實(shí)現(xiàn)接口的類就不能實(shí)現(xiàn)JDK的動(dòng)態(tài)代理。
cglib是針對(duì)類來實(shí)現(xiàn)代理的,它的原理是對(duì)指定的目標(biāo)類生成一個(gè)子類,并覆蓋其中方法實(shí)現(xiàn)增強(qiáng),但因?yàn)椴捎玫氖抢^承,所以不能對(duì)final修飾的類進(jìn)行代理。
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動(dòng)態(tài)代理類 public class BookFacadeCglib implements MethodInterceptor { private Object target; //綁定委托對(duì)象并返回一個(gè)代理類 public Object getInstance(Object target) { this.target = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.target.getClass()); // 回調(diào)方法 enhancer.setCallback(this); // 創(chuàng)建代理對(duì)象 return enhancer.create(); } @Override // 回調(diào)方法 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("事物結(jié)束"); return temp; } } public class TestCglib { public static void main(String[] args) { BookFacadeCglib cglib = new BookFacadeCglib(); BookFacadeImpl1 bookCglib = (BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1()); bookCglib.addBook(); } }
以上這篇淺談Java反射與代理就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- Java中反射動(dòng)態(tài)代理接口的詳解及實(shí)例
- java利用反射實(shí)現(xiàn)動(dòng)態(tài)代理示例
- java 反射和動(dòng)態(tài)代理詳解及實(shí)例代碼
- 詳解Java反射實(shí)現(xiàn)Aop代理
- Java動(dòng)態(tài)代理和反射機(jī)制詳解
- 實(shí)例講解Java中動(dòng)態(tài)代理和反射機(jī)制
- Java使用反射來獲取泛型信息示例
- java使用反射訪問成員變量的值示例
- Java反射機(jī)制及Method.invoke詳解
- java根據(jù)方法名稱取得反射方法的參數(shù)類型示例
- Java使用反射生成JDK代理示例
相關(guān)文章
詳解獲取Spring MVC中所有RequestMapping以及對(duì)應(yīng)方法和參數(shù)
本篇文章主要介紹了詳解獲取Spring MVC中所有RequestMapping以及對(duì)應(yīng)方法和參數(shù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-03-03MybatisPlus實(shí)現(xiàn)數(shù)據(jù)攔截的使用示例
在MyBatis-Plus中,可以通過自定義攔截器來實(shí)現(xiàn)對(duì)SQL語句的攔截和修改,本文就來介紹一下如何使用,具有一定的參考價(jià)值,感興趣的可以了解一下2023-10-10SpringBoot快速構(gòu)建應(yīng)用程序方法介紹
這篇文章主要介紹了SpringBoot快速構(gòu)建應(yīng)用程序方法介紹,涉及SpringBoot默認(rèn)的錯(cuò)誤頁(yè)面,嵌入式Web容器層面的約定和定制等相關(guān)內(nèi)容,具有一定借鑒價(jià)值,需要的朋友可以參考下。2017-11-11使用AOP+反射實(shí)現(xiàn)自定義Mybatis多表關(guān)聯(lián)查詢
這篇文章主要介紹了使用AOP+反射實(shí)現(xiàn)自定義Mybatis多表關(guān)聯(lián),目前的需求是增強(qiáng)現(xiàn)有的查詢,使用簡(jiǎn)單的注解即可實(shí)現(xiàn)多表關(guān)聯(lián),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-05-05詳解springboot整合ehcache實(shí)現(xiàn)緩存機(jī)制
這篇文章主要介紹了詳解springboot整合ehcache實(shí)現(xiàn)緩存機(jī)制,ehcache提供了多種緩存策略,主要分為內(nèi)存和磁盤兩級(jí),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01spring/springboot整合dubbo詳細(xì)教程
今天教大家如何使用spring/springboot整合dubbo,文中有非常詳細(xì)的圖文介紹及代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴有很好地幫助,需要的朋友可以參考下2021-05-05java中實(shí)現(xiàn)分頁(yè)的幾種常見方式總結(jié)
在項(xiàng)目中經(jīng)常會(huì)查詢大量數(shù)據(jù),這就要用到分頁(yè)展示,下面這篇文章主要給大家介紹了關(guān)于java中實(shí)現(xiàn)分頁(yè)的幾種常見方式,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-12-12