SpringBoot實現(xiàn)使用反射模擬IOC和getBean
IOC就是spring的核心思想之一:控制反轉。這里不再贅述,看我的文章即可了解:
spring基礎思想IOC
其次就是java的反射,反射機制是spring的重要實現(xiàn)核心,今天我看spring的三級緩存解決循壞引用的問題時,發(fā)現(xiàn)一個bean的生命周期與java對象的產生流程具備高度相似性,接著我就去重溫了一下bean的創(chuàng)建流程,發(fā)現(xiàn)一個bean實例從無到有經歷的過程非常有意思,spring用極其優(yōu)雅的代碼實現(xiàn)了用反射和各種map數據結構實現(xiàn)了bean的流水線式生產,非常優(yōu)雅,于是我就嘗試用反射寫一個逆向生成實例對象的小玩意。
那么前置需要了解一個對象生成的過程:
我將對象的創(chuàng)建過程總結為:
檢查常量池是否存在該對象的符號引用并確定是否經過類加載過程,都沒有則進行類加載過程。
為新生對象分配內存(兩種方式:指針碰撞和空閑列表<指針碰撞涉及到當指針調動頻繁時為了避免出現(xiàn)臟讀,采取本地線程分配緩沖TLAB的優(yōu)先分配情況>)并將除對象頭外的其他內存空間賦值W為0。
設置對象頭。
對象的初始化,這個就是執(zhí)行你的構造方法的過程,給你需要的字段賦值你想要定義的值。
補充一下其中的細節(jié):為新生對象分配內存過程中,首先一個對象在類加載完成后它所需要的內存大小是完全確定的,分配內存的過程實際上就是在java堆里劃分一塊等大的內存給它,但是該怎么劃分呢?如果java堆的內存布局是嚴格的順序分配,即一邊是使用過的,一邊是空閑的,那么就會采取指針碰撞的方式分配內存,所謂的指針在空閑區(qū)與使用區(qū)的分界線處,收到內存需求時,指針向后移動直到移動所覆蓋的長度等于java對象所需要的內存大小時停止并進行分配。但如果java堆的內存布局是碎片化的不連續(xù)的呢?我們就只能維護一個列表,這個列表記錄了所有java堆空閑區(qū)的大小與位置信息,分配時只需要查找最適合新生對象的區(qū)域分配即可。
注意:java堆是否規(guī)整是由垃圾收集器的能力決定的,是否帶有空間壓縮整理的能力。當我們采用的收集器是Serial與Parnew時是用指針碰撞的方式分配的,當采用的是CMS垃圾收集器的時候,則是需要使用麻煩的空閑區(qū)表分配。
這里我們著重的去關注屬性與方法的填充即可:一個對象的靈魂就是它的屬性與方法:
整個工具用到的核心屬性:
private static volatile Constructor<?> constructor;
private static volatile Object newInstance;
private static volatile Map<String, Method> methodMap;我們先看看這幾個方法的作用:
public static Constructor<?> getConstructor(Object dataType) {
Class<?> typeClass = dataType.getClass();
try {
Constructor<?> constructor = typeClass.getConstructor();
constructor.setAccessible(true);
return constructor;
} catch (NoSuchMethodException e) {
e.printStackTrace();
return null;
}
}獲取類型的構造器,注意這可是無參構造,如果你沒有無參構造那么很有可能報錯,因為我們也不知道它有多少屬性對吧?(時刻記住咱們是逆向!??!不知道這個類型里有什么?。?!一切都是反射帶來的信息)
public static void fillValueToNewInstance(Object dataType, Map<String, Object> initialMap) throws Exception {
constructor = getConstructor(dataType);
Class<?> typeClass = dataType.getClass();
Field[] declaredFields = typeClass.getDeclaredFields();
Iterator<Field> fieldIterator = Arrays.stream(declaredFields).iterator();
newInstance = constructor.newInstance();
while (fieldIterator.hasNext()) {
Field field = fieldIterator.next();
field.setAccessible(true);
if (initialMap != null)
field.set(newInstance, initialMap.get(field.getName()));
}
}獲取屬性并填充屬性值,這里也順帶著將屬性給進去了。
public static Method[] getMethodArray(Object dataType) {
return dataType.getClass().getDeclaredMethods();
}獲取一切方法組成方法數組。
public static void fillMethodMap(Object dataType) {
methodMap = new HashMap<>();
Method[] methodArray = getMethodArray(dataType);
Iterator<Method> iterator = Arrays.stream(methodArray).iterator();
while (iterator.hasNext()) {
Method method = iterator.next();
method.setAccessible(true);
methodMap.put(method.getName(), method);
}
}將方法存到方法集合中去存儲。
public static Object useMethod(String methodName, @Nullable Object... parameters) throws Exception {
return methodMap.get(methodName).invoke(newInstance, parameters);
}使用方法要通過名稱。
@SneakyThrows
public static Object getBean(Object dataType, Map<String, Object> parameterMap) {
fillValueToNewInstance(dataType, parameterMap);
fillMethodMap(dataType);
return newInstance;
}getBean方法。
public static void main(String[] args) throws Exception {
Map<String,Object> map = new HashMap<>();
map.put("name","xu");
map.put("age",Integer.valueOf(18));
map.put("sex",'女');
Person bean = (Person) getBean(new Person(), map);
System.out.println(bean.toString());
System.out.println(useMethod("toString"));
}測試方法。類型信息如下:
class Person {
private String name;
private Integer age;
private Character sex;
//無參構造絕對不能少
public Person() {
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", sex=" + sex +
'}';
}
}測試結果如下:

這里我們可沒有用Person person = new Person();的方式實例化對象,用反射實現(xiàn)了對象的實例化。
里面用到關于反射的方法我列下來:
getDeclaredFields 獲取域屬性對象
getName 獲取屬性名稱
getType 獲取屬性類型的字節(jié)碼文件
setAccessible(true) 設置暴力破解,獲取對私有屬性的使用
getDeclaredMethods 獲取全部方法數組
getClass 獲取字節(jié)碼文件
getConstructor 獲取無參構造器
到此這篇關于SpringBoot實現(xiàn)使用反射模擬IOC和getBean的文章就介紹到這了,更多相關SpringBoot反射模擬IOC與getBean內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
springsecurity實現(xiàn)用戶登錄認證快速使用示例代碼(前后端分離項目)
這篇文章主要介紹了springsecurity實現(xiàn)用戶登錄認證快速使用示例代碼(前后端分離項目),本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2024-03-03
SpringBoot中@KafkaListener使用${}動態(tài)指定topic問題
在SpringKafka中,使用${}引用Spring屬性配置,可以在不同環(huán)境中重新配置topic名稱,而無需修改代碼,在application.properties或application.yml中定義topic名稱,并在代碼中使用${}引用2024-12-12
Springboot2.1.6集成activiti7出現(xiàn)登錄驗證的實現(xiàn)
這篇文章主要介紹了Springboot2.1.6集成activiti7出現(xiàn)登錄驗證的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-12-12
SpringCloudAlibaba是一款優(yōu)秀的微服務架構,在市面上有著廣泛的應用,這篇文章介紹了SpringCloudAlibaba的一些基本使用,適合初學者,希望能夠給大家?guī)韼椭?/div> 2024-08-08
Eclipse+Java+Swing+Mysql實現(xiàn)工資管理系統(tǒng)
這篇文章主要介紹了Eclipse+Java+Swing+Mysql實現(xiàn)工資管理系統(tǒng),對正在工作或者學習的你有一定的參考價值,需要的朋友可以參考一下2022-01-01最新評論

