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获取
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
相关文章
java多线程中的volatile和synchronized用法分析
这篇文章主要介绍了java多线程中的volatile和synchronized用法分析,以实例的形式分析了在多线程中volatile和synchronized的用法区别与使用原理,具有一定的参考借鉴价值,需要的朋友可以参考下2014-12-12SLF4J报错解决:No SLF4J providers were found的
这篇文章主要介绍了SLF4J报错解决:No SLF4J providers were found的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2023-06-06
最新评论