java 反射和動(dòng)態(tài)代理詳解及實(shí)例代碼
一、java中的反射
1.通過反射加載類的屬性和方法實(shí)例代碼:
/**
* java.lang.Class 是反射的源頭
* 我們創(chuàng)建了一個(gè)類,通過編譯(javac.exe)生成對(duì)應(yīng)的class文件,之后我們通過java.exe加載(jvm的類加載器加載)此class文件
* 此class文件加載到內(nèi)存后,就是一個(gè)運(yùn)行時(shí)類,存在緩存區(qū),這個(gè)運(yùn)行時(shí)類本事就是一個(gè)Class的實(shí)例
* 每一個(gè)運(yùn)行時(shí)類只加載一次,
*/
Class<StudentExam> clazz = StudentExam.class;
StudentExam studentExam = clazz.newInstance();
System.err.println(studentExam);
System.out.println(clazz);
// Field field = clazz.getField("id"); // 通過屬性調(diào)用運(yùn)行時(shí)類的指定屬性:屬性是public類型
Field field = clazz.getDeclaredField("id"); // 屬性是非public 類型
Field[] fields = clazz.getDeclaredFields(); // 獲取運(yùn)行時(shí)類本身(父類不行)所有聲明的屬性,父類使用clazz.getFields();
for (Field field2 : fields) {
int i = field2.getModifiers();
String type = Modifier.toString(i);// 獲取字段屬性的數(shù)據(jù)類型
System.out.println(type);
}
field.setAccessible(true);
field.set(studentExam, 11);
System.err.println(studentExam.getId());
// 通過反射調(diào)用運(yùn)行時(shí)類的指定方法
Method method = clazz.getMethod("setId", Integer.class);
method.invoke(studentExam, 123); // 調(diào)用運(yùn)行時(shí)類的指定方法
Method[] methods = clazz.getMethods(); // 獲取所有運(yùn)行時(shí)類及其父類中所有聲明為public的方法
Method[] methods2 = clazz.getDeclaredMethods();// 獲取運(yùn)行時(shí)類本身類中聲明的方法
for (Method method2 : methods) {
System.out.println(method2.getName());
}
// * 通過對(duì)象的getClass()方法獲取對(duì)象的運(yùn)行時(shí)類,
Exam exam = new Exam();
Class clazzExam = exam.getClass();
2.類加載器ClassLoader
/**
* Description:類加載器,加載xx.properties文件,并讀取數(shù)據(jù)
* @param
* @author xiazhongwei
* @data 2016年9月29日:下午5:32:56
* @return
*/
public void classLoader() throws IOException {
//方法一、從當(dāng)前工程下加載
ClassLoader loader = this.getClass().getClassLoader();
// 路徑是包下寫:com\\able\\onlineExam\\resources\\config.properties
InputStream inStream = loader.getResourceAsStream("config.properties");
// 方法二、從指定的路徑下加載文件
// FileInputStream fileInputStream = new FileInputStream(new File("config.properties"));
Properties properties = new Properties();
properties.load(inStream);
// properties.load(fileInputStream);
String prop = properties.getProperty("domain");
System.out.println(prop);
}
3.動(dòng)態(tài)代理
靜態(tài)代理:代理類和目標(biāo)對(duì)象的類型都是在編譯期間確定下來,不利于程序的擴(kuò)展。同時(shí)每個(gè)代理類只能為一個(gè)接口服務(wù),這樣一來程序開發(fā)中必然產(chǎn)生過多的代理。
動(dòng)態(tài)代理:客戶通過代理類來調(diào)用其他對(duì)象的方法,并且是在程序運(yùn)行時(shí),根據(jù)需要?jiǎng)討B(tài)創(chuàng)建目標(biāo)類的代理對(duì)象。
代理設(shè)計(jì)模式的原理:
使用一個(gè)代理將對(duì)象包裝起來,然后用該代理對(duì)象取代原始對(duì)象,任何對(duì)原始對(duì)象的調(diào)用都要通過代理,代理對(duì)象決定的那個(gè)是否以及何時(shí)將方法調(diào)用
package com.test.junit;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyTest {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
Object object = myInvocationHandler.bind(realSubject);
Subject subject = (Subject) object;
subject.action();
}
}
// 動(dòng)態(tài)代理的使用
interface Subject{
void action();
}
// 被代理類
class RealSubject implements Subject{
@Override
public void action() {
System.out.println("我是被代理類,記得執(zhí)行我哦。。。。");
}
}
class MyInvocationHandler implements InvocationHandler{
Object object;// 實(shí)現(xiàn)了接口的被代理類的對(duì)象的聲明
/**
* Description:①給被代理的對(duì)象實(shí)例化 ②返回一個(gè)代理類對(duì)象
* @param
* @author xiazhongwei
* @data 2016年9月29日:下午4:13:43
* @return
*/
public Object bind(Object object){
this.object = object;
return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), this);
}
/**
* 當(dāng)通過代理類的對(duì)象發(fā)起對(duì)被重寫的方法的調(diào)用時(shí),都會(huì)轉(zhuǎn)化為對(duì)如下的invok方法的調(diào)用
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object returnObject = method.invoke(object, args);
return returnObject;
}
}
4.動(dòng)態(tài)代理與AOP
示例一、
package com.atguigu.spring.aop;
public interface ArithmeticCalculator {
int add(int i, int j);
int sub(int i, int j);
int mul(int i, int j);
int div(int i, int j);
}
package com.atguigu.spring.aop;
import org.springframework.stereotype.Component;
@Component("arithmeticCalculator")
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
@Override
public int add(int i, int j) {
int result = i + j;
return result;
}
@Override
public int sub(int i, int j) {
int result = i - j;
return result;
}
@Override
public int mul(int i, int j) {
int result = i * j;
return result;
}
@Override
public int div(int i, int j) {
int result = i / j;
return result;
}
}
package com.atguigu.spring.aop;
public class ArithmeticCalculatorLoggingImpl implements ArithmeticCalculator {
@Override
public int add(int i, int j) {
System.out.println("The method add begins with [" + i + "," + j + "]");
int result = i + j;
System.out.println("The method add ends with " + result);
return result;
}
@Override
public int sub(int i, int j) {
System.out.println("The method sub begins with [" + i + "," + j + "]");
int result = i - j;
System.out.println("The method sub ends with " + result);
return result;
}
@Override
public int mul(int i, int j) {
System.out.println("The method mul begins with [" + i + "," + j + "]");
int result = i * j;
System.out.println("The method mul ends with " + result);
return result;
}
@Override
public int div(int i, int j) {
System.out.println("The method div begins with [" + i + "," + j + "]");
int result = i / j;
System.out.println("The method div ends with " + result);
return result;
}
}
package com.atguigu.spring.aop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
public class ArithmeticCalculatorLoggingProxy {
//要代理的對(duì)象
private ArithmeticCalculator target;
public ArithmeticCalculatorLoggingProxy(ArithmeticCalculator target) {
super();
this.target = target;
}
//返回代理對(duì)象
public ArithmeticCalculator getLoggingProxy(){
ArithmeticCalculator proxy = null;
// 代理對(duì)象有哪一個(gè)類加載器負(fù)責(zé)加載
ClassLoader loader = target.getClass().getClassLoader();
// 代理對(duì)象的類型,即其中有哪些方法
Class [] interfaces = new Class[]{ArithmeticCalculator.class};
// 當(dāng)調(diào)用代理對(duì)象的其中方法時(shí),執(zhí)行下面的代碼
InvocationHandler h = new InvocationHandler() {
/**
* proxy: 代理對(duì)象。 一般不使用該對(duì)象
* method: 正在被調(diào)用的方法
* args: 調(diào)用方法傳入的參數(shù)
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 在方法內(nèi)部不會(huì)直接調(diào)用proxy對(duì)象的某個(gè)方法,proxy.toString()會(huì)造成死循環(huán)調(diào)用invoke方法
String methodName = method.getName();
//打印日志
System.out.println("[before] The method " + methodName + " begins with " + Arrays.asList(args));
//調(diào)用目標(biāo)方法
Object result = null;
try {
//前置通知
result = method.invoke(target, args);
//返回通知, 可以訪問到方法的返回值
} catch (NullPointerException e) {
e.printStackTrace();
//異常通知, 可以訪問到方法出現(xiàn)的異常
}
//后置通知. 因?yàn)榉椒梢阅軙?huì)出異常, 所以訪問不到方法的返回值
//打印日志
System.out.println("[after] The method ends with " + result);
return result;
}
};
/**
* loader: 代理對(duì)象使用的類加載器。
* interfaces: 指定代理對(duì)象的類型. 即代理代理對(duì)象中可以有哪些方法.
* h: 當(dāng)具體調(diào)用代理對(duì)象的方法時(shí), 應(yīng)該如何進(jìn)行響應(yīng), 實(shí)際上就是調(diào)用 InvocationHandler 的 invoke 方法
*/
proxy = (ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces, h);
return proxy;
}
}
package com.atguigu.spring.aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
// ArithmeticCalculator arithmeticCalculator = new ArithmeticCalculatorImpl();
ArithmeticCalculator arithmeticCalculator = new ArithmeticCalculatorLoggingImpl();
arithmeticCalculator = new ArithmeticCalculatorLoggingProxy(arithmeticCalculator).getLoggingProxy();
int result = arithmeticCalculator.add(11, 12);
System.out.println("result:" + result);
result = arithmeticCalculator.div(21, 3);
System.out.println("result:" + result);
}
}
示例二、
package com.test.junit;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyTest {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
Object object = myInvocationHandler.bind(realSubject);
Subject subject = (Subject) object;
subject.action();
}
}
// 動(dòng)態(tài)代理的使用
interface Subject{
void action();
}
// 被代理類
class RealSubject implements Subject{
@Override
public void action() {
System.out.println("我是被代理類,記得執(zhí)行我哦。。。。");
}
}
class MyInvocationHandler implements InvocationHandler{
Object object;// 實(shí)現(xiàn)了接口的被代理類的對(duì)象的聲明
/**
* Description:①給被代理的對(duì)象實(shí)例化 ②返回一個(gè)代理類對(duì)象
* @param
* @author xiazhongwei
* @data 2016年9月29日:下午4:13:43
* @return
*/
public Object bind(Object object){
this.object = object;
return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), this);
}
/**
* 當(dāng)通過代理類的對(duì)象發(fā)起對(duì)被重寫的方法的調(diào)用時(shí),都會(huì)轉(zhuǎn)化為對(duì)如下的invok方法的調(diào)用
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object returnObject = method.invoke(object, args);
return returnObject;
}
}
感謝閱讀此文,希望能幫助到大家,謝謝大家對(duì)本站的支持!
- Java中反射動(dòng)態(tài)代理接口的詳解及實(shí)例
- Java動(dòng)態(tài)代理和反射機(jī)制詳解
- java利用反射實(shí)現(xiàn)動(dòng)態(tài)代理示例
- Java反射和動(dòng)態(tài)代理的使用解讀
- 詳解Java中的反射機(jī)制和動(dòng)態(tài)代理
- 實(shí)例講解Java中動(dòng)態(tài)代理和反射機(jī)制
- Java反射的應(yīng)用之動(dòng)態(tài)代理深入理解
- Java高級(jí)-反射&動(dòng)態(tài)代理詳解
- JavaSE反射與動(dòng)態(tài)代理詳細(xì)代碼示例
相關(guān)文章
Spring Cache整合Redis實(shí)現(xiàn)方法詳解
這篇文章主要介紹了Spring Cache整合Redis實(shí)現(xiàn)方法詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08
阿里資深技術(shù)專家:在各階段中3年經(jīng)驗(yàn)的java程序員應(yīng)該具備哪些技術(shù)能力
這篇文章主要介紹了阿里資深技術(shù)專家:在各階段中3年經(jīng)驗(yàn)的java程序員應(yīng)該具備哪些技術(shù)能力,本文給大家列舉了一些內(nèi)容,大家可以根據(jù)自己需要有方法的掌握,感興趣的朋友跟隨小編一起看看吧2020-07-07
解決引入Redisson可能會(huì)出現(xiàn)項(xiàng)目啟動(dòng)失敗的問題
這篇文章主要介紹了解決引入Redisson可能會(huì)出現(xiàn)項(xiàng)目啟動(dòng)失敗的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06
使用 Apache POI 在 Java 中寫入 Excel
這篇文章詳細(xì)介紹了如何使用ApachePOI在Java中編寫Excel文件的技巧,包括創(chuàng)建工作簿、工作表、行和單元格,以及如何處理不同版本的Excel文件,通過詳細(xì)的步驟和代碼示例,讀者可以快速掌握ApachePOI的基本使用方法,感興趣的朋友一起看看吧2025-02-02
詳解Java枚舉類在生產(chǎn)環(huán)境中的使用方式
本文主要介紹了Java枚舉類在生產(chǎn)環(huán)境中的使用方式,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-02-02
maven項(xiàng)目打包上傳到私有倉(cāng)庫(kù)
在項(xiàng)目開發(fā)中通常會(huì)引用其他的jar,怎樣把自己的項(xiàng)目做為一個(gè)jar包的形式發(fā)布到私服倉(cāng)庫(kù)中,本文就詳細(xì)的介紹一下,感興趣的可以了解一下2021-06-06

