淺談Spring6中的反射機制
一:回顧反射機制
這種重點回顧一下反射Method!
為什么要回顧反射機制呢?因為我們后面要手寫一個簡易的Spring框架,便于我們理解其中的核心原理!
1. 分析方法四要素
我們先來看一下,不使用反射機制調(diào)用一個方法需要幾個要素的參與!
定義一個SomeService方法
package com.bjpowernode.reflect; public class SomeService { // 沒有參數(shù)、沒有返回值的方法 public void doSome(){ System.out.println("public void doSome()執(zhí)行。"); } // 一個參數(shù),返回String的方法 public String doSome(String s){ System.out.println("public String doSome(String s)執(zhí)行。"); return s; } // 兩個參數(shù),返回String的方法 public String doSome(String s, int i){ System.out.println("public String doSome(String s, int i)執(zhí)行。"); return s + i; } }
進(jìn)行測試,分析方法的要素
package com.bjpowernode.reflect; public class Test { public static void main(String[] args) { // 不使用反射機制調(diào)用這些方法 SomeService someService = new SomeService(); // 無參數(shù) someService.doSome(); // 一個參數(shù) String s1 = someService.doSome("張三"); System.out.println(s1); // 兩個參數(shù) String s2 = someService.doSome("李四", 250); System.out.println(s2); } }
通過以上測試代碼,我們可以得出調(diào)用一個方法,一般涉及到4個要素:
①調(diào)用哪個對象的(SomeService)
②哪個方法(doSome)
③傳什么參數(shù)("張三")
④返回什么值(String類型)
總結(jié):調(diào)用哪個對象的哪個方法?傳什么值?返回什么值?
2. 獲取Method
要使用反射機制調(diào)用一個方法,首先你要獲取到這個方法。
在反射機制中Method實例代表的是一個方法,那么怎么獲取Method實例呢?
編寫測試
(1)要想調(diào)用方法,首先我們要先獲取對應(yīng)的類,使用Class.forName,參數(shù)是全限定類名
(2)然后調(diào)用這個類的getDeclaredMethod方法,參數(shù)一個是方法名、另一個參數(shù)是可變可變長度參數(shù),類型是class;這樣就能獲取到方法。
(3)方法獲取到,我們就可以調(diào)用invoke(調(diào)用)方法,參數(shù)一個是obj,就是要把對象傳過來,所以我們就需要先創(chuàng)建一個對象、另一個參數(shù)也是可變長度參數(shù),傳具體的值。
例如以下程序的四要素:調(diào)用哪個對象、哪個方法、傳什么參數(shù)、返回什么值?
①obj 要素:哪個對象
②doSomeMethod 要素:哪個方法
③"李四", 250 要素:傳什么參數(shù)
④retValue 要素:返回什么值
package com.bjpowernode.reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class Test2 { public static void main(String[] args) throws Exception{ // 使用反射機制調(diào)用方法 // 第一步:獲取類 Class<?> clazz = Class.forName("com.bjpowernode.reflect.SomeService"); // 第二步:獲取方法 Method doSomeMethod = clazz.getDeclaredMethod("doSome", String.class, int.class); // 第三步:調(diào)用方法,四要素 // 創(chuàng)建對象 Object obj = clazz.newInstance(); // 這個方法已經(jīng)過時,也可以采用其它方式 // 也可以先獲取到無參數(shù)構(gòu)造方法,然后在創(chuàng)建對象 Constructor<?> declaredConstructor = clazz.getDeclaredConstructor(); Object obj1 = declaredConstructor.newInstance(); // 調(diào)用invoke方法 Object retValue = doSomeMethod.invoke(obj, "李四", 250); System.out.println(retValue); } }
3. SpringDI核心實現(xiàn)原理
我們在看一下下面這種需求,假設(shè)你現(xiàn)在已知以下信息: ①有這樣一個類,類名叫做:com.powernode.reflect.User ②這個類符合javabean規(guī)范。屬性私有化,對外提供公開的setter和getter方法。 ③你還知道這個類當(dāng)中有一個屬性,屬性的名字叫做 age ④并且你還知道age屬性的類型是int類型。要求:請使用反射機制調(diào)用set方法,給User對象的age屬性賦值!
User類
package com.bjpowernode.reflect; public class User { private String name; private int age; public User() { } public User(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
使用反射機制進(jìn)行賦值,通用代碼
第一步:還是通過反射機制先獲取類,Class.forName
第二步:調(diào)用getDeclaredMethod方法獲取方法,參數(shù)有兩個,怎么樣動態(tài)獲取呢?
①已知了屬性名是age,又符合javabean規(guī)范,所以我們可以動態(tài)拼接出方法名:先拼接上“set”,再調(diào)用toUpperCase方法全部轉(zhuǎn)換成大寫,然后調(diào)用charAt方法截取第一個字符;最后在調(diào)用substring方法拼接上后面的字符串;得到完整的方法名:getAge
②已知了屬性名是age,調(diào)用類的getDeclaredField方法,參數(shù)是屬性名age,就可以獲取對應(yīng)的屬性類型,但是我們需要的是.class,所以在調(diào)用參數(shù)類型的getType方法;得到完整的屬性類型(.class形式):int.class
第三步:最后就可以創(chuàng)建對象,調(diào)用invoke方法,給屬性賦值,這個方法沒有返回值類型,所以什么都不要返回;最后輸出這個對象即可!
package com.bjpowernode.reflect; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Locale; public class Test4 { public static void main(String[] args) throws Exception { // 已知類名和屬性名 String className = "com.bjpowernode.reflect.User"; String propertyName = "age"; // 使用反射機制,給age屬性賦值 // 第一步:獲取類 Class<?> clazz = Class.forName(className); // 第二步:獲取方法 // 根據(jù)屬性獲取方法名---字符串拼接 String setMethodName = "set"+propertyName.toUpperCase().charAt(0)+propertyName.substring(1); // 根據(jù)屬性獲取屬性的類型 Field filedType = clazz.getDeclaredField(propertyName); // 獲取方法 Method setMethod = clazz.getDeclaredMethod(setMethodName, filedType.getType()); // 第三步:調(diào)用 // 創(chuàng)建對象 Object obj = clazz.newInstance(); setMethod.invoke(obj,18); // 沒有返回值類型 // 輸出打印這個對象 System.out.println(obj); } }
執(zhí)行結(jié)果:age屬性成功賦值
看到這里我們是不是想到了Spring容器的注入?我們在看一下我們配置的spring.xml文件,就是指定了類名和屬性名;然后底層通過反射機制進(jìn)行了對象的創(chuàng)建!
總結(jié):有了上面我們對反射機制的回顧學(xué)習(xí),后面我們就嘗試手寫一個簡易的Spring框架!
到此這篇關(guān)于淺談Spring6中的反射機制的文章就介紹到這了,更多相關(guān)Spring6反射機制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
簡單講解在Java編程中實現(xiàn)設(shè)計模式中的單例模式結(jié)構(gòu)
這篇文章主要介紹了簡單講解在Java編程中實現(xiàn)設(shè)計模式中的單例模式結(jié)構(gòu),設(shè)計模式是最基本直白簡單的一種設(shè)計模式,需要的朋友可以參考下2016-04-04Java?輸入輸出?IO?NIO?AIO三兄弟對比分析對比分析
這篇文章主要為大家介紹了Java?輸入輸出?IO?NIO?AIO三兄弟對比分析對比分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04Spring @Transaction 注解執(zhí)行事務(wù)的流程
這篇文章主要介紹了Spring @Transaction 注解執(zhí)行事務(wù)的流程,Spring 是如何開啟事務(wù)的?又是如何進(jìn)行提交事務(wù)和關(guān)閉事務(wù)的,本文給大家詳細(xì)介紹,需要的朋友可以參考下2021-06-06