0x01 前言
??內(nèi)世白础(Introspector)是 Java 語(yǔ)言對(duì) Bean 類屬性、事件的一種缺省處理方法焚辅。一般的做法是通過(guò)類 Introspector 來(lái)獲取某個(gè)對(duì)象的 BeanInfo 信息,然后通過(guò) BeanInfo 來(lái)獲取屬性的描述器(PropertyDescriptor)棚点,通過(guò)這個(gè)屬性描述器就可以獲取某個(gè)屬性對(duì)應(yīng)的 getter / setter 方法湾蔓,然后我們就可以通過(guò)反射機(jī)制來(lái)調(diào)用這些方法。
0x02 Java內(nèi)省和反射的聯(lián)系
- 反射
??反射就是運(yùn)行時(shí)獲取一個(gè)類的所有信息贬循,可以獲取到 .class 的任何定義的信息(包括成員 變量,成員方法诉儒,構(gòu)造器等)亏掀÷算担可以操縱類的字段怜校、方法魂贬、構(gòu)造器等部分裙顽。
- 內(nèi)省
??內(nèi)省基于反射實(shí)現(xiàn),主要用于操作 JavaBean键科,通過(guò)內(nèi)省可以獲取 Bean 的 getter / setter
0x03 JavaBean 規(guī)范
規(guī)范
??JavaBean 是一種 JAVA 語(yǔ)言寫成的可重用組件(類)漩怎,必須遵循一定的規(guī)范。
類必須使用 public 修飾饭玲。
必須保證有公共無(wú)參數(shù)構(gòu)造器叁执。
包含了屬性的操作手段(給屬性賦值,獲取屬性值)蚕断。
分類
??JavaBean 可分為兩種:一種是有用戶界面(UI入挣,User Interface)的 JavaBean;還有一種是沒(méi)有用戶界面,主要負(fù)責(zé)處理事務(wù)(如數(shù)據(jù)運(yùn)算障陶,操縱數(shù)據(jù)庫(kù))的 JavaBean抱究。
成員
??屬性(properties) JavaBean 提供了高層次的屬性概念,屬性在 JavaBean 中不只是傳統(tǒng)的面向?qū)ο蟮母拍罾锏膶傩怨乃拢瑫r(shí)還得到了屬性讀取和屬性寫入的 API 的支持勋磕。
??方法(method) JavaBean 中的方法就是通常的 Java 方法,它可以從其他組件或在腳本環(huán)境中調(diào)用苦银。
??事件(event) Bean 與其他軟件組件交流信息的主要方式是發(fā)送和接受事件赶站。
Eclipse 插件 Lombok
??Lombok是一款小巧的代碼生成工具。自動(dòng)生成默認(rèn)的 getter / setter 方法想括、自動(dòng)化的資源管理(通過(guò) @Cleanup 注解)及注解驅(qū)動(dòng)的異常處理等烙博。通過(guò)注解的方式,作用域至編譯過(guò)程中踪栋,因此運(yùn)行效率和項(xiàng)目部署都沒(méi)有任何影響图毕。
0x04 Java內(nèi)省具體操作
??關(guān)鍵方法和步驟。
BeanInfo getBeanInfo(class<?> beanclass)
進(jìn)行 Bean 內(nèi)省囤官,獲得 Bean 所有屬性蛤虐、公開的方法和事件。PropertyDescriptor[] getPropertyDescriptors()
獲取所有屬性的描述器(ropertyDescriptor類刑顺,用于描述 Java Bean,通過(guò)一對(duì)存儲(chǔ)器方法導(dǎo)出的JavaBean類的一個(gè)屬性)蹲堂。迭代
PropertyDescriptor[]
對(duì)每個(gè)屬性進(jìn)行操作。
@Test
public void testIntrospector() {
try {
// BeanInfo beanInfo = Introspector.getBeanInfo(User.class);
BeanInfo beanInfo = Introspector.getBeanInfo(User.class, Object.class); // 在給定的“斷點(diǎn)”(前閉后開)政供,在 Java Bean 上進(jìn)行內(nèi)省所有屬性和公開的方法朽基。
// User user = User.class.newInstance(); // 反射創(chuàng)建User對(duì)象
User user = User.class.getConstructor(String.class, String.class).newInstance("admin", "admin"); // 反射獲取有參構(gòu)造器創(chuàng)建對(duì)象
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
System.out.println("屬性名 = " + pd.getName()); // 獲取屬性名
System.out.println("getter = " + pd.getReadMethod()); // 獲取屬性getter
System.out.println("setter = " + pd.getWriteMethod()); // 獲取屬性setter
}
for (PropertyDescriptor pd : pds) { // 調(diào)用getter并獲取返回值
Object result = pd.getWriteMethod().invoke(user, "admin");
System.out.println(result);
}
} catch (Exception e) {
e.printStackTrace();
}
}
0x05 JavaBean 和 Map 之間的互相轉(zhuǎn)換
Bean 轉(zhuǎn)換為 Map
形參:
Object
類對(duì)象bean
稼虎。返回值:Map
類集合。創(chuàng)建
HashMap
對(duì)象map
用于存儲(chǔ) Bean 的描述信息。創(chuàng)建
BeanInfo
類型對(duì)象beanInfo
计济,用Introspector.getBeanInfo()
內(nèi)省所有屬性、字段和公開的方法学密。創(chuàng)建
PropertyDescriptor[] pds
传藏,存儲(chǔ)多個(gè)屬性的描述信息(描述符)。遍歷
pds
哭靖,賦值給map
中的<Key, Value>
侈离。
方法代碼
public static Map<String, Object> beanToMap(Object bean) {
Map<String, Object> map = new HashMap<>();
try {
BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass(), Object.class);
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
String key = pd.getName();
Object value = pd.getReadMethod().invoke(bean);
map.put(key, value);
}
} catch (Exception e) {
e.printStackTrace();
}
return map;
}
測(cè)試實(shí)例
@Test
public void testBeanToMap() {
Map<String, Object> map = beanToMap(new User("admin", "admin"));
System.out.println(map);
}
Map 轉(zhuǎn)換為 Bean
形參:為
Map
類集合map
和泛型T
的字節(jié)碼類型beanType
卦碾,返回值:泛型T
實(shí)例。生成指定類型
bean
實(shí)例济榨。創(chuàng)建
BeanInfo
類型對(duì)象beanInfo
绿映,用Introspector.getBeanInfo()
內(nèi)省所有屬性、字段和公開的方法橘忱。創(chuàng)建
PropertyDescriptor[] pds
,存儲(chǔ)多個(gè)屬性的描述信息(描述符)颖御。遍歷
pds
凝颇,獲取Map
中的<Key, Value>
,調(diào)用bean
中的setter
給bean
賦值芦岂。
方法代碼
public static <T> T mapToBean(Map<String, Object> map, Class<T> beanType) {
Object bean = null;
try {
bean = beanType.newInstance();
BeanInfo beanInfo = Introspector.getBeanInfo(beanType, Object.class);
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
Object value = map.get(pd.getName());
pd.getWriteMethod().invoke(bean, value);
}
} catch (Exception e) {
e.printStackTrace();
}
return (T) bean;
}
測(cè)試實(shí)例
@Test
public void testMapToBean() {
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("username", "root");
map.put("password", "root");
System.out.println(mapToBean(map, User.class));
}