您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關JavaBeanInfo 和 Spring 之間有什么關系,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
在 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<WeakReference<Class<?>>> | 參數信息 |
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> T getObject(Class<T> clazz, Map<String, Object> 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<Student> clazz = Student.class; // 設置屬性表 Map<String, Object> 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 模式的時候會編寫下面這樣的內容。
<bean id="people" class="com.source.hot.ioc.book.pojo.PeopleBean"> <property name="name" value="zhangsan"/> </bean>
這里我們拋開 Spring 中 Bean 生命周期相關的一些接口、占位符解析等內容,我們就簡單的來看這個 <bean>
標簽,這個標簽定義了一個 class
屬性 和子標簽 property
,我們可以通過一些 XML 解析工具得到這兩個對象,Spring 在這會將 class
屬性通過 ClassLoader
轉換成 Class
會將 property
轉換成對象 PropertyValue
,然后通過反射將對象創建出來。那么這段說明和我們所編寫的通過 BeanInfo
創建 Bean 有什么關系呢?我們可以思考下面幾個問題
知道了 BeanClass
如何才能創建對象呢?
知道屬性名稱和屬性值如何給對象賦值呢?
這兩個問題的答案很簡單就是通過 Java 反射機制來進行處理,那么具體怎么做呢?這個問題的答案其實就是我們前面所編寫的那段創建對象的代碼。回過頭我們來看這兩個問題
第一個問題的答案:創建對象其本質是尋找構造函數并調用
第二個問題的答案:通過找到寫方法將數據寫入
Spring 中無參構造函數的調用
有參構造的推論過程
在這里做出了兩種構造函數的推論,當完成推論構造函數后就可以進行對象創建及屬性賦值了。
屬性賦值相關的代碼就不在截圖了各位可以自行查找。
當我們有了 getObject
這樣一個方法后,我們再來看一些生命周期,Spring 當中的各類生命周期其實就是圍繞者這段代碼的前后來做各種補充操作,
比如 InitializingBean
這個接口的調用時在 Bean 創建完成后,那么我們可以在具體的位置上補充這樣一段
修改后的 getObject
@NotNull private <T> T getObject(Class<T> clazz, Map<String, Object> 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; }
以上就是JavaBeanInfo 和 Spring 之間有什么關系,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。