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