Spring之关于PropertyDescriptor的扩展剖析

 更新时间:2023年07月07日 08:57:27   作者:StrangerIt  
这篇文章主要介绍了Spring之关于PropertyDescriptor的扩展剖析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

一、jdk中类PropertyDescriptor获取

jdk中Introspector类为工具提供了一种标准的方法来了解目标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) {
                    /**
                     * 方法没有参数:方法有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) {
                    /**
                     * 有一个参数
                     * 1、有一个参数且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) {
                    /**
                     * 两个参数
                     * 1、返回值void ,第一个参数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();
}

总结满足以下条件才会生成PropertyDescriptor(注意读写方法是否为空,spring中by_type类型注入会筛选出具有写方法不为空的PropertyDescriptor):

1、参数个数必须2个以内、方法不是static

2、 方法没有参数:方法有readMethod没有writeMehtod

  • 普通get开头方法
  • 返回值boolean 以is开头的

3、 有一个参数

  • 有一个参数且int类型,方法get开头的,没有readMethod writeMehtod等属性
  • 没有返回值、set方法开头的,具有writeMethod

4、两个参数

  • 返回值void ,第一个参数int类型,set开头的会生成PropertyDescriptor(注意此时没有writeMethod)

综上所述:具有写方法的必须返回值void 且set开头一个参数的的才有写方法(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 一个参数满足要求
    public  void  setService12123(OrderService orderService1){
       System.out.println("1231"+orderService);
    }
    //返回值void 参数个数大于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());
       }
    }
}

此时满足条件方法有getClass(继承父类的Object) 、setService12123会生成PropertyDescriptor且具有写方法

存在问题

方法有返回值、且静态的方法是不具备生成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或者是静态
   4、参数一个或者2个(2个实话第一个参数必须为int类型)**
//1、set开头方法
       2、public方法
       3、返回值不是void或者是静态
       4、参数一个或者2个(2个实话第一个参数必须为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]);
    }

三、总结

spring依赖注入(@Bean(autowire=Autowire.BY_TYPE)实话会找到该类所有PropertyDescriptor满足条件的方法

  • 1、从jdk中Introspector中获取
  • 2、扩展ExtendedBeanInfo获取

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • idea tomcat乱码问题的解决及相关设置的步骤

    idea tomcat乱码问题的解决及相关设置的步骤

    这篇文章主要介绍了idea tomcat乱码问题的解决及相关设置的步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-11-11
  • selenium+java环境搭建过程推荐

    selenium+java环境搭建过程推荐

    这篇文章主要介绍了selenium+java环境搭建过程推荐,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-10-10
  • 关于Poi读取Excel引发内存溢出问题的解决方法

    关于Poi读取Excel引发内存溢出问题的解决方法

    这篇文章主要给大家介绍了关于Poi读取Excel引发内存溢出问题的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面跟着小编来一起学习学习吧。
    2017-08-08
  • 解决java idea新建子目录时命名不是树形结构的问题

    解决java idea新建子目录时命名不是树形结构的问题

    这篇文章主要介绍了解决java idea新建子目录时命名不是树形结构的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • java多线程中的volatile和synchronized用法分析

    java多线程中的volatile和synchronized用法分析

    这篇文章主要介绍了java多线程中的volatile和synchronized用法分析,以实例的形式分析了在多线程中volatile和synchronized的用法区别与使用原理,具有一定的参考借鉴价值,需要的朋友可以参考下
    2014-12-12
  • Spring Boot DevTools使用教程

    Spring Boot DevTools使用教程

    DevTools通过提供自动重启和LiveReload功能,使您更快、更轻松地开发Spring Boot应用程序。这篇文章主要介绍了Spring Boot DevTools使用教程,需要的朋友可以参考下
    2018-11-11
  • Java自动添加重写的toString方法详解

    Java自动添加重写的toString方法详解

    在本篇文章里小编给大家整理了关于Java自动添加重写的toString方法总结,需要的朋友们学习下。
    2019-07-07
  • Java语言实现反转链表代码示例

    Java语言实现反转链表代码示例

    这篇文章主要介绍了Java语言实现反转链表代码示例,小编觉得挺不错的,这里分享给大家,供需要的朋友参考。
    2017-10-10
  • Java灵活使用枚举表示一组字符串的操作

    Java灵活使用枚举表示一组字符串的操作

    这篇文章主要介绍了Java灵活使用枚举表示一组字符串的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-06-06
  • SLF4J报错解决:No SLF4J providers were found的问题

    SLF4J报错解决:No SLF4J providers were found的

    这篇文章主要介绍了SLF4J报错解决:No SLF4J providers were found的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-06-06

最新评论