java用beaninfo_JavaBeanInfo 和 Spring 之间的关系
Java Beans
在這一章章節(jié)中筆者將和各位一起探討關(guān)于 Java Beans 相關(guān)的內(nèi)容。本章主要圍繞 java.beans 這個(gè)包路徑下的代碼進(jìn)行一些說(shuō)明。
在 Spring 中我們可以看到 BeanInfoFactory 該接口可以用來(lái)獲取 Class 對(duì)應(yīng)的 BeanInfo 對(duì)象,在 CachedIntrospectionResults 中也有相關(guān)的成員變量作為信息存儲(chǔ),其他地方還有筆者就不再這里都去搜索了,各位可以自行查閱。
BeanInfoFactory public interface BeanInfoFactory {
@Nullable
BeanInfo getBeanInfo(Class> beanClass) throws IntrospectionException;
}
CachedIntrospectionResults public final class CachedIntrospectionResults {
private final BeanInfo beanInfo;
}
對(duì)于 Spring 來(lái)說(shuō)操作 Bean 本身的內(nèi)容其實(shí)是操作各類屬性及其提供的方法。從筆者的角度來(lái)看 Bean 這個(gè)對(duì)象我覺(jué)得可以分成這三種,第一種是關(guān)于 Bean 屬性的,第二種是關(guān)于屬性操作的方法,第三種是提供外部操作的方法。就比如說(shuō)現(xiàn)在有一個(gè) People 對(duì)象,存在多個(gè)屬性,我們?cè)趯?duì)這個(gè) Bean 對(duì)象定義的時(shí)候正常情況下我們會(huì)放入 private 修飾的屬性名,然后在提供 get 和 set 方法,如果有需要我們可以在通過(guò)非屬性操作相關(guān)的方法。本章就暫時(shí)是對(duì)前兩者的一個(gè)討論。
首先我們來(lái)定義一個(gè)基本的 Java Bean
public class Student {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
現(xiàn)在我們用了一個(gè)名字叫做 Student 的 Java 對(duì)象,我們來(lái)看這個(gè)對(duì)象的解釋
在 Student 對(duì)象中具有屬性 name
在 Student 對(duì)象中存在字段 name
我們通常情況下會(huì)有這兩種對(duì)象的定義解釋,那么這個(gè)定義解釋在 Java 中是如何對(duì)其進(jìn)行定義的呢。在 Java 中有一個(gè)接口叫做 java.beans.BeanInfo 這個(gè)接口是用來(lái)描述 Java Bean 的接口,下面我們來(lái)看這個(gè)接口中存在的方法
BeanInfo 方法信息
public interface BeanInfo {
BeanDescriptor getBeanDescriptor();
EventSetDescriptor[] getEventSetDescriptors();
int getDefaultEventIndex();
PropertyDescriptor[] getPropertyDescriptors();
int getDefaultPropertyIndex();
MethodDescriptor[] getMethodDescriptors();
BeanInfo[] getAdditionalBeanInfo();
}
getBeanDescriptor :返回 Bean 的描述信息
getEventSetDescriptors:返回 Bean 相關(guān)的事件信息
getDefaultEventIndex:返回 Bean 默認(rèn)事件索引
getPropertyDescriptors:返回 Bean 屬性描述
getDefaultPropertyIndex:返回 Bean 默認(rèn)的屬性索引
getMethodDescriptors:返回 Bean 方法描述
getAdditionalBeanInfo :返回其他的 Bean Info 信息
下面我們先來(lái)對(duì)接口中的返回值做一些介紹
BeanDescriptor 成員變量表
變量名稱
變量類型
變量說(shuō)明
beanClassRef
Reference extends Class>>
bean 的類
customizerClassRef
Reference extends Class>>
自定義的類
PropertyDescriptor 成員變量表
變量名稱
變量類型
變量說(shuō)明
propertyTypeRef
Reference extends Class>>
屬性類型
readMethodRef
MethodRef
讀方法
writeMethodRef
MethodRef
寫(xiě)方法
propertyEditorClassRef
Reference extends Class>>
屬性編輯類型
bound
boolean
constrained
boolean
baseName
String
writeMethodName
String
寫(xiě)方法名稱
readMethodName
String
讀方法名稱
MethodDescriptor 成員變量表
變量名稱
變量類型
變量說(shuō)明
methodRef
MethodRef
方法
paramNames
String[]
參數(shù)名稱
params
List>>
參數(shù)信息
parameterDescriptors
ParameterDescriptor
參數(shù)描述
在了解了上述三個(gè)對(duì)象后我們來(lái)編寫(xiě)一個(gè)測(cè)試用例,該測(cè)試用例主要用來(lái)獲取 BeanInfo 接口數(shù)據(jù)
BeanInfo 測(cè)試用例
@Test
void classTest() throws IntrospectionException {
Class clazz = Student.class;
BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
System.out.println();
}
BeanInfo 信息
我們現(xiàn)在對(duì) BeanInfo 有了一定的了解,接下來(lái)我們要通過(guò) BeanInfo 來(lái)創(chuàng)建一個(gè)對(duì)象,并給該對(duì)象進(jìn)行數(shù)據(jù)賦值,下面我們來(lái)寫(xiě)代碼
@NotNull
private T getObject(Class clazz, Map prop) throws Exception {
// 獲取 BeanInfo 接口
BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
// 獲取 Bean Class
Class> beanClass = beanInfo.getBeanDescriptor().getBeanClass();
// 獲取所有的構(gòu)造函數(shù)
Constructor>[] declaredConstructors = beanClass.getDeclaredConstructors();
// 確認(rèn)構(gòu)造函數(shù): 直接取無(wú)參構(gòu)造
Constructor constructor = confirmConstructor(declaredConstructors);
// 通過(guò)構(gòu)造函數(shù)獲取對(duì)象
Object bean = constructor.newInstance();
// 為對(duì)象設(shè)置屬性
// 提取屬性描述
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
// 屬性名稱
String name = propertyDescriptor.getName();
if (prop.containsKey(name)) {
// 寫(xiě)函數(shù)
Method writeMethod = propertyDescriptor.getWriteMethod();
// 從屬性表中獲取屬性名稱對(duì)應(yīng)的屬性值
Object proValue = prop.get(name);
writeMethod.invoke(bean, proValue);
}
}
return (T) bean;
}
編寫(xiě)這段代碼的主要邏輯如下
通過(guò) Class 獲取 BeanInfo 接口
通過(guò) BeanInfo 獲取 beanClass
通過(guò) beanClass 提取構(gòu)造函數(shù)列表,從構(gòu)造函數(shù)列表中選擇一個(gè)具體的構(gòu)造函數(shù)(這里采用無(wú)參構(gòu)造的方式)
獲取屬性描述對(duì)象進(jìn)行屬性設(shè)置
編寫(xiě)完成后我們來(lái)寫(xiě)測(cè)試用例
@Test
void beanInfoCreateBean() throws Exception {
Class clazz = Student.class;
// 設(shè)置屬性表
Map prop = new HashMap<>(8);
prop.put("name", "student_name");
Student bean = getObject(clazz, prop);
assert bean.getName().equals("student_name");
}
這樣我們就完成了數(shù)據(jù)賦值,在上述過(guò)程中我們對(duì)于 beanClass 的獲取可以直接使用參數(shù)傳遞的 clazz 直接使用,可以不需要通過(guò) BeanInfo 接口進(jìn)行二次調(diào)度。
下面我們來(lái)談一談 Spring 和 BeanInfo 的一些關(guān)聯(lián)。
相信各位在使用 Spring XML 模式的時(shí)候會(huì)編寫(xiě)下面這樣的內(nèi)容。
這里我們拋開(kāi) Spring 中 Bean 生命周期相關(guān)的一些接口、占位符解析等內(nèi)容,我們就簡(jiǎn)單的來(lái)看這個(gè) 標(biāo)簽,這個(gè)標(biāo)簽定義了一個(gè) class 屬性 和子標(biāo)簽 property ,我們可以通過(guò)一些 XML 解析工具得到這兩個(gè)對(duì)象,Spring 在這會(huì)將 class 屬性通過(guò) ClassLoader 轉(zhuǎn)換成 Class 會(huì)將 property 轉(zhuǎn)換成對(duì)象 PropertyValue ,然后通過(guò)反射將對(duì)象創(chuàng)建出來(lái)。那么這段說(shuō)明和我們所編寫(xiě)的通過(guò) BeanInfo 創(chuàng)建 Bean 有什么關(guān)系呢?我們可以思考下面幾個(gè)問(wèn)題
知道了 BeanClass 如何才能創(chuàng)建對(duì)象呢?
知道屬性名稱和屬性值如何給對(duì)象賦值呢?
這兩個(gè)問(wèn)題的答案很簡(jiǎn)單就是通過(guò) Java 反射機(jī)制來(lái)進(jìn)行處理,那么具體怎么做呢?這個(gè)問(wèn)題的答案其實(shí)就是我們前面所編寫(xiě)的那段創(chuàng)建對(duì)象的代碼。回過(guò)頭我們來(lái)看這兩個(gè)問(wèn)題
第一個(gè)問(wèn)題的答案:創(chuàng)建對(duì)象其本質(zhì)是尋找構(gòu)造函數(shù)并調(diào)用
第二個(gè)問(wèn)題的答案:通過(guò)找到寫(xiě)方法將數(shù)據(jù)寫(xiě)入
Spring 中無(wú)參構(gòu)造函數(shù)的調(diào)用
有參構(gòu)造的推論過(guò)程
在這里做出了兩種構(gòu)造函數(shù)的推論,當(dāng)完成推論構(gòu)造函數(shù)后就可以進(jìn)行對(duì)象創(chuàng)建及屬性賦值了。
屬性賦值相關(guān)的代碼就不在截圖了各位可以自行查找。
當(dāng)我們有了 getObject 這樣一個(gè)方法后,我們?cè)賮?lái)看一些生命周期,Spring 當(dāng)中的各類生命周期其實(shí)就是圍繞者這段代碼的前后來(lái)做各種補(bǔ)充操作,
比如 InitializingBean 這個(gè)接口的調(diào)用時(shí)在 Bean 創(chuàng)建完成后,那么我們可以在具體的位置上補(bǔ)充這樣一段
修改后的 getObject
@NotNull
private T getObject(Class clazz, Map prop) throws Exception {
// 獲取 BeanInfo 接口
BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
// 獲取 Bean Class
Class> beanClass = beanInfo.getBeanDescriptor().getBeanClass();
// 獲取所有的構(gòu)造函數(shù)
Constructor>[] declaredConstructors = beanClass.getDeclaredConstructors();
// 確認(rèn)構(gòu)造函數(shù): 直接取無(wú)參構(gòu)造
Constructor constructor = confirmConstructor(declaredConstructors);
// 通過(guò)構(gòu)造函數(shù)獲取對(duì)象
Object bean = constructor.newInstance();
// 為對(duì)象設(shè)置屬性
// 提取屬性描述
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
// 屬性名稱
String name = propertyDescriptor.getName();
if (prop.containsKey(name)) {
// 寫(xiě)函數(shù)
Method writeMethod = propertyDescriptor.getWriteMethod();
// 從屬性表中獲取屬性名稱對(duì)應(yīng)的屬性值
Object proValue = prop.get(name);
writeMethod.invoke(bean, proValue);
}
}
if (bean instanceof InitializingBean) {
((InitializingBean) bean).afterPropertiesSet();
}
return (T) bean;
}
其他的一些生命周期接口也是可以通過(guò)類似的處理方式進(jìn)行補(bǔ)充,筆者就不在這里進(jìn)行展開(kāi)了。
總結(jié)
以上是生活随笔為你收集整理的java用beaninfo_JavaBeanInfo 和 Spring 之间的关系的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 招商银行信用卡怎么修改个人资料
- 下一篇: java fx 建立窗体,3花式窗体与J