Spring之關(guān)于PropertyDescriptor的擴(kuò)展剖析
一、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) { /** * 有一個(gè)參數(shù) * 1、有一個(gè)參數(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) { /** * 兩個(gè)參數(shù) * 1、返回值void ,第一個(gè)參數(shù)int類型,set開頭的會(huì)生成PropertyDescriptor(注意此時(shí)沒有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é)滿足以下條件才會(huì)生成PropertyDescriptor(注意讀寫方法是否為空,spring中by_type類型注入會(huì)篩選出具有寫方法不為空的PropertyDescriptor):
1、參數(shù)個(gè)數(shù)必須2個(gè)以內(nèi)、方法不是static
2、 方法沒有參數(shù):方法有readMethod沒有writeMehtod
- 普通get開頭方法
- 返回值boolean 以is開頭的
3、 有一個(gè)參數(shù)
- 有一個(gè)參數(shù)且int類型,方法get開頭的,沒有readMethod writeMehtod等屬性
- 沒有返回值、set方法開頭的,具有writeMethod
4、兩個(gè)參數(shù)
- 返回值void ,第一個(gè)參數(shù)int類型,set開頭的會(huì)生成PropertyDescriptor(注意此時(shí)沒有writeMethod)
綜上所述:具有寫方法的必須返回值void 且set開頭一個(gè)參數(shù)的的才有寫方法(spring中by_type類型注入會(huì)篩選出具有寫方法不為空的)
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 一個(gè)參數(shù)滿足要求 public void setService12123(OrderService orderService1){ System.out.println("1231"+orderService); } //返回值void 參數(shù)個(gè)數(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()); } } }
此時(shí)滿足條件方法有g(shù)etClass(繼承父類的Object) 、setService12123會(huì)生成PropertyDescriptor且具有寫方法
存在問題
方法有返回值、且靜態(tài)的方法是不具備生成PropertyDescriptor屬性描述器,spring中
org.springframework.beans.ExtendedBeanInfo#isCandidateWriteMethod
拓展有返回值、或者static也會(huì)生成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針對(duì)jdk進(jìn)行拓展
ExtendedBeanInfo對(duì)jdk不滿足的方法進(jìn)行擴(kuò)展(有返回值、static)生成PropertyDescriptor
**滿足以下條件才會(huì)生成PropertyDescriptor ? ?1、set開頭方法 ? ?2、public方法 ? ?3、返回值不是void或者是靜態(tài) ? ?4、參數(shù)一個(gè)或者2個(gè)(2個(gè)實(shí)話第一個(gè)參數(shù)必須為int類型)**
//1、set開頭方法 2、public方法 3、返回值不是void或者是靜態(tài) 4、參數(shù)一個(gè)或者2個(gè)(2個(gè)實(shí)話第一個(gè)參數(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)實(shí)話會(huì)找到該類所有PropertyDescriptor滿足條件的方法
- 1、從jdk中Introspector中獲取
- 2、擴(kuò)展ExtendedBeanInfo獲取
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java使用選擇排序法對(duì)數(shù)組排序?qū)崿F(xiàn)代碼
這篇文章主要介紹了Java使用選擇排序法對(duì)數(shù)組排序?qū)崿F(xiàn)代碼,需要的朋友可以參考下2014-02-02使用Java實(shí)現(xiàn)5種負(fù)載均衡算法實(shí)例
負(fù)載均衡指由多臺(tái)服務(wù)器以對(duì)稱的方式組成一個(gè)服務(wù)器集合,每臺(tái)服務(wù)器都具有等價(jià)的地位,都可以單獨(dú)對(duì)外提供服務(wù)而無(wú)須其他服務(wù)器的輔助,這篇文章主要給大家介紹了關(guān)于使用Java實(shí)現(xiàn)5種負(fù)載均衡算法的相關(guān)資料,需要的朋友可以參考下2021-09-09java樹結(jié)構(gòu)stream工具類的示例代碼詳解
Stream 作為 Java 8 的一大亮點(diǎn),它與 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念。今天通過本文重點(diǎn)給大家介紹java樹結(jié)構(gòu)stream工具類的示例代碼,感興趣的朋友一起看看吧2022-03-03通過實(shí)例學(xué)習(xí)Java集合框架HashSet
這篇文章主要介紹了通過實(shí)例學(xué)習(xí)Java集合框架HashSet,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12SpringBoot3集成RocketMq場(chǎng)景分析
RocketMQ因其架構(gòu)簡(jiǎn)單、業(yè)務(wù)功能豐富、具備極強(qiáng)可擴(kuò)展性等特點(diǎn)被廣泛應(yīng)用,比如金融業(yè)務(wù)、互聯(lián)網(wǎng)、大數(shù)據(jù)、物聯(lián)網(wǎng)等領(lǐng)域的業(yè)務(wù)場(chǎng)景,這篇文章主要介紹了SpringBoot3集成RocketMq,需要的朋友可以參考下2023-08-08