Spring之關(guān)于PropertyDescriptor的擴展剖析
一、jdk中類PropertyDescriptor獲取
jdk中Introspector類為工具提供了一種標(biāo)準(zhǔn)的方法來了解目標(biāo)Java Bean支持的屬性、事件和方法。
java.beans.Introspector#getTargetPropertyInfo
private PropertyDescriptor[] getTargetPropertyInfo() {
// Apply some reflection to the current class.
// First get an array of all the public methods at this level
Method methodList[] = getPublicDeclaredMethods(beanClass);
// Now analyze each method.
//遍歷所有方法看是否是符合PropertyDescriptor
for (int i = 0; i < methodList.length; i++) {
Method method = methodList[i];
if (method == null) {
continue;
}
// skip static methods.
int mods = method.getModifiers();
if (Modifier.isStatic(mods)) {
continue;
}
String name = method.getName();
Class<?>[] argTypes = method.getParameterTypes();
Class<?> resultType = method.getReturnType();
int argCount = argTypes.length;
PropertyDescriptor pd = null;
if (name.length() <= 3 && !name.startsWith(IS_PREFIX)) {
// Optimization. Don't bother with invalid propertyNames.
continue;
}
try {
if (argCount == 0) {
/**
* 方法沒有參數(shù):方法有readMethod沒有writeMehtod
* 1、普通get開頭方法
* 2、返回值boolean 以is開頭的
*/
if (name.startsWith(GET_PREFIX)) {
// Simple getter
pd = new PropertyDescriptor(this.beanClass, name.substring(3), method, null);
} else if (resultType == boolean.class && name.startsWith(IS_PREFIX)) {
// Boolean getter
pd = new PropertyDescriptor(this.beanClass, name.substring(2), method, null);
}
} else if (argCount == 1) {
/**
* 有一個參數(shù)
* 1、有一個參數(shù)且int類型,方法get開頭的,沒有readMethod writeMehtod等屬性
* 2、沒有返回值、set方法開頭的,具有writeMethod
*/
if (int.class.equals(argTypes[0]) && name.startsWith(GET_PREFIX)) {
pd = new IndexedPropertyDescriptor(this.beanClass, name.substring(3), null, null, method, null);
} else if (void.class.equals(resultType) && name.startsWith(SET_PREFIX)) {
// Simple setter
pd = new PropertyDescriptor(this.beanClass, name.substring(3), null, method);
if (throwsException(method, PropertyVetoException.class)) {
pd.setConstrained(true);
}
}
} else if (argCount == 2) {
/**
* 兩個參數(shù)
* 1、返回值void ,第一個參數(shù)int類型,set開頭的會生成PropertyDescriptor(注意此時沒有writeMethod)
*/
if (void.class.equals(resultType) && int.class.equals(argTypes[0]) && name.startsWith(SET_PREFIX)) {
pd = new IndexedPropertyDescriptor(this.beanClass, name.substring(3), null, null, null, method);
if (throwsException(method, PropertyVetoException.class)) {
pd.setConstrained(true);
}
}
}
} catch (IntrospectionException ex) {
pd = null;
}
if (pd != null) {
if (propertyChangeSource) {
pd.setBound(true);
}
addPropertyDescriptor(pd);
}
}
processPropertyDescriptors();
}總結(jié)滿足以下條件才會生成PropertyDescriptor(注意讀寫方法是否為空,spring中by_type類型注入會篩選出具有寫方法不為空的PropertyDescriptor):
1、參數(shù)個數(shù)必須2個以內(nèi)、方法不是static
2、 方法沒有參數(shù):方法有readMethod沒有writeMehtod
- 普通get開頭方法
- 返回值boolean 以is開頭的
3、 有一個參數(shù)
- 有一個參數(shù)且int類型,方法get開頭的,沒有readMethod writeMehtod等屬性
- 沒有返回值、set方法開頭的,具有writeMethod
4、兩個參數(shù)
- 返回值void ,第一個參數(shù)int類型,set開頭的會生成PropertyDescriptor(注意此時沒有writeMethod)
綜上所述:具有寫方法的必須返回值void 且set開頭一個參數(shù)的的才有寫方法(spring中by_type類型注入會篩選出具有寫方法不為空的)
demo 具有寫方法的PropertyDescriptor演示:
//@Component
public class UserService {
private OrderService orderService;
//返回值不為void
public OrderService setOrderService(OrderService orderService){
//this.orderService=orderService;
return orderService;
}
//返回值不為void
public OrderService setOrderService(int test,OrderService orderService){
this.orderService=orderService;
return orderService;
}
//返回值void 一個參數(shù)滿足要求
public void setService12123(OrderService orderService1){
System.out.println("1231"+orderService);
}
//返回值void 參數(shù)個數(shù)大于2不滿足
public void setOrderService(int test,OrderService orderService,StockService stockService){
this.orderService=orderService;
}
}
public class Test {
public static void main(String[] args) throws IntrospectionException {
BeanInfo beanInfo= Introspector.getBeanInfo(UserService.class);
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for(PropertyDescriptor propertyDescriptor:propertyDescriptors){
System.out.println(propertyDescriptor.getWriteMethod());
}
}
}此時滿足條件方法有g(shù)etClass(繼承父類的Object) 、setService12123會生成PropertyDescriptor且具有寫方法

存在問題
方法有返回值、且靜態(tài)的方法是不具備生成PropertyDescriptor屬性描述器,spring中
org.springframework.beans.ExtendedBeanInfo#isCandidateWriteMethod
拓展有返回值、或者static也會生成PropertyDescriptor**
滿足以下條件:
return methodName.length() > 3 && methodName.startsWith(“set”) && Modifier.isPublic(method.getModifiers()) && (!Void.TYPE.isAssignableFrom(method.getReturnType()) || Modifier.isStatic(method.getModifiers())) && (nParams == 1 || nParams == 2 && Integer.TYPE == method.getParameterTypes()[0]);
二、spring針對jdk進行拓展
ExtendedBeanInfo對jdk不滿足的方法進行擴展(有返回值、static)生成PropertyDescriptor
**滿足以下條件才會生成PropertyDescriptor ? ?1、set開頭方法 ? ?2、public方法 ? ?3、返回值不是void或者是靜態(tài) ? ?4、參數(shù)一個或者2個(2個實話第一個參數(shù)必須為int類型)**
//1、set開頭方法
2、public方法
3、返回值不是void或者是靜態(tài)
4、參數(shù)一個或者2個(2個實話第一個參數(shù)必須為int類型)
public static boolean isCandidateWriteMethod(Method method) {
String methodName = method.getName();
int nParams = method.getParameterCount();
return methodName.length() > 3 && methodName.startsWith("set") && Modifier.isPublic(method.getModifiers()) && (!Void.TYPE.isAssignableFrom(method.getReturnType()) || Modifier.isStatic(method.getModifiers())) && (nParams == 1 || nParams == 2 && Integer.TYPE == method.getParameterTypes()[0]);
}三、總結(jié)
spring依賴注入(@Bean(autowire=Autowire.BY_TYPE)實話會找到該類所有PropertyDescriptor滿足條件的方法
- 1、從jdk中Introspector中獲取
- 2、擴展ExtendedBeanInfo獲取
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java使用選擇排序法對數(shù)組排序?qū)崿F(xiàn)代碼
這篇文章主要介紹了Java使用選擇排序法對數(shù)組排序?qū)崿F(xiàn)代碼,需要的朋友可以參考下2014-02-02
java樹結(jié)構(gòu)stream工具類的示例代碼詳解
Stream 作為 Java 8 的一大亮點,它與 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念。今天通過本文重點給大家介紹java樹結(jié)構(gòu)stream工具類的示例代碼,感興趣的朋友一起看看吧2022-03-03
通過實例學(xué)習(xí)Java集合框架HashSet
這篇文章主要介紹了通過實例學(xué)習(xí)Java集合框架HashSet,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-12-12

