淺談Java反射與代理
Java反射機制與動態(tài)代理,使得Java更加強大,Spring核心概念I(lǐng)oC、AOP就是通過反射機制與動態(tài)代理實現(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);
通過一個對象獲得完整的包名和類名:
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ù)組長度: "+Array.getLength(temp));//5
System.out.println("數(shù)組的第一個元素: "+Array.get(temp, 0));//1
Array.set(temp, 0, 100);
System.out.println("修改之后數(shù)組第一個元素為: "+Array.get(temp, 0));//100
cls.getComponentType();
cls.isArray();
2 Java代理
代理模式是常用的Java設(shè)計模式,它的特征是代理類與委托類有同樣的接口,代理類主要負責(zé)為委托類預(yù)處理消息、過濾消息、把消息轉(zhuǎn)發(fā)給委托類,以及事后處理消息等。代理類與委托類之間通常會存在關(guān)聯(lián)關(guān)系,一個代理類的對象與一個委托類的對象關(guān)聯(lián),代理類的對象本身并不真正實現(xiàn)服務(wù),而是通過調(diào)用委托類的對象的相關(guān)方法,來提供特定的服務(wù)。
按照代理的創(chuàng)建時期,代理類可以分為2種。
•靜態(tài)代理:由程序員創(chuàng)建或特定工具自動生成源代碼,再對其編譯。在程序運行前,代理類的.class文件就已經(jīng)存在了。
•動態(tài)代理:在程序運行時,由Java反射機制動態(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ù)處理之后");
}
}
//測試類
public class TestCount {
public static void main(String[] args) {
CountImpl countImpl = new CountImpl();
CountProxy countProxy = new CountProxy(countImpl);
countProxy.queryCount();
}
}
觀察代碼可以發(fā)現(xiàn)每一個代理類只能為一個接口服務(wù),這樣一來程序開發(fā)中必然會產(chǎn)生過多的代理,而且,所有的代理操作除了調(diào)用的方法不一樣之外,其他的操作都一樣,則此時肯定是重復(fù)代碼。解決這一問題最好的做法是可以通過一個代理類完成全部的代理功能,那么此時就必須使用動態(tài)代理完成。
2.2 動態(tài)代理
動態(tài)代理類的字節(jié)碼在程序運行時由Java反射機制動態(tài)生成,無需程序員手工編寫它的源代碼。動態(tài)代理類不僅簡化了編程工作,而且提高了軟件系統(tǒng)的可擴展性,因為Java 反射機制可以生成任意類型的動態(tài)代理類。
2.2.1 JDK動態(tài)代理
java.lang.reflect 包中的Proxy類和InvocationHandler 接口提供了生成動態(tài)代理類的能力。
InvocationHandler接口:
public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}
參數(shù)說明:
Object proxy:指被代理的對象。
Method method:要調(diào)用的方法
Object[] args:方法調(diào)用時所需要的參數(shù)
可以將InvocationHandler接口的子類想象成一個代理的最終操作類,替換掉ProxySubject。
Proxy類:
Proxy類是專門完成代理的操作類,可以通過此類為一個或多個接口動態(tài)地生成實現(xiàn)類,此類提供了如下的操作方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
參數(shù)說明:
ClassLoader loader:類加載器
Class<?>[] interfaces:得到全部的接口
InvocationHandler h:得到InvocationHandler接口的子類實例
如果想要完成動態(tài)代理,首先需要定義一個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動態(tài)代理類
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的動態(tài)代理依靠接口實現(xiàn),如果有些類并沒有實現(xiàn)接口,則不能使用JDK代理,這就要使用cglib動態(tài)代理了。
2.2.2 CGLIB動態(tài)代理
JDK的動態(tài)代理機制只能代理實現(xiàn)了接口的類,而未實現(xiàn)接口的類就不能實現(xiàn)JDK的動態(tài)代理。
cglib是針對類來實現(xiàn)代理的,它的原理是對指定的目標(biāo)類生成一個子類,并覆蓋其中方法實現(xiàn)增強,但因為采用的是繼承,所以不能對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動態(tài)代理類
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());
// 回調(diào)方法
enhancer.setCallback(this);
// 創(chuàng)建代理對象
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反射與代理就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
解決@Async(“taskExecutor“)異步線程報錯問題
這篇文章主要介紹了解決@Async(“taskExecutor“)異步線程報錯問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-08-08
java兩個數(shù)組合并為一個數(shù)組的幾種方法
這篇文章主要給大家介紹了關(guān)于java兩個數(shù)組合并為一個數(shù)組的幾種方法,最近在寫代碼時遇到了需要合并兩個數(shù)組的需求,文中將每種方法都介紹的非常詳細,需要的朋友可以參考下2023-07-07
有關(guān)Java常見的誤解小結(jié)(來看一看)
下面小編就為大家?guī)硪黄嘘P(guān)Java常見的誤解小結(jié)(來看一看)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-05-05
Spring-AOP @AspectJ切點函數(shù)之@annotation()用法
這篇文章主要介紹了Spring-AOP @AspectJ切點函數(shù)之@annotation()用法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07
詳解Spring中InitializingBean接口的功能
這篇文章主要介紹了Spring中InitializingBean接口的功能,講述了spring中InitializingBean接口的功能簡介說明,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-05-05
springboot 多模塊將dao(mybatis)項目拆分出去
這篇文章主要介紹了springboot 多模塊將dao(mybatis)項目拆分出去,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-05-05

