spring源码解析番外篇之PropertyDescriptor

224 阅读2分钟

在阅读 spring 源码时,特别是在属性注入的时候,会经常刷到PropertyDescriptor这个类,下面来看看这个类具体是做什么的

PropertyDescriptor在Java中是一个用于描述JavaBean属性的对象,它封装了关于JavaBean类中一个特定属性的所有相关信息。这个类是Java beans API(java.beans.Introspector)的一部分,主要用于处理JavaBean的反射机制。 具体来说,PropertyDescriptor的作用包括:

  1. 属性名称:表示JavaBean中的一个属性名,如name、age等。
  2. 读取器和写入器方法:与该属性相关联的getter和setter方法。例如,对于一个名为name的属性,对应的getter可能是getName(),setter可能是setName(String name)。
  3. 可读性/可写性:表明属性是否可以通过getter或setter方法进行访问或修改。
  4. 属性类型 :提供属性值的数据类型信息。
  5. 属性编辑器(可选):通过PropertyEditor可以将属性值转换为字符串形式(如在JTable或JTextField中显示),反之亦然。
  6. 使用PropertyDescriptor,开发者能够通过程序动态地发现和操作JavaBean的属性,而无需硬编码对属性的直接引用,这是MVC框架、持久化层、XML配置绑定以及其他需要利用JavaBean特性的地方常见的做法。例如,在Spring框架的自动装配过程中,会用到PropertyDescriptor来查找并注入相应的依赖项。

下面看个例子


 import java.beans.BeanInfo;
 import java.beans.IntrospectionException;
 import java.beans.Introspector;
 import java.beans.PropertyDescriptor;
 import java.lang.reflect.InvocationTargetException;
 ​
 public class PropertyDescriptorExample {
 ​
     // 假设我们有一个简单的JavaBean
     public static class Person {
         private String name;
         private int age;
 ​
         public String getName() {
             return name;
         }
 ​
         public void setName(String name) {
             this.name = name;
         }
 ​
         public int getAge() {
             return age;
         }
 ​
         public void setAge(int age) {
             this.age = age;
         }
     }
 ​
     public static void main(String[] args) throws IntrospectionException, IllegalAccessException, InvocationTargetException {
         // 创建一个Person实例
         Person person = new Person();
         person.setName("John Doe");
         person.setAge(30);
 ​
         // 使用Introspector获取BeanInfo对象
         BeanInfo beanInfo = Introspector.getBeanInfo(Person.class);
 ​
         // 遍历所有PropertyDescriptor
         for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
             System.out.println("Property Name: " + pd.getName());
 ​
             // 获取对应的getter和setter方法
             Method getter = pd.getReadMethod();
             Method setter = pd.getWriteMethod();
 ​
             // 读取属性值
             if (getter != null) {
                 Object value = getter.invoke(person);
                 System.out.println("Getter Value: " + value);
             }
 ​
             // 设置属性值(这里仅为演示,实际可能不需要再次设置)
             if (setter != null) {
                 Class<?> propertyType = pd.getPropertyType();
                 if (propertyType == String.class) {
                     setter.invoke(person, "Updated Name");
                 } else if (propertyType == Integer.TYPE) {
                     setter.invoke(person, 31); // 更新年龄
                 }
                 System.out.println("Setter invoked. New Value: ");
                 // 输出更新后的值
                 System.out.println(getter.invoke(person));
             }
         }
     }
 }
 ​

乍一看这个跟反射有点像,确实有点像,都可以获取 javabean 的属性、类型、方法等,但是又有些不一样,反射是属于更底层的技术,通过Class对象,可以得到类的所有构造器、方法、字段等,并直接进行操作。而PropertyDescriptor是JavaBeans规范的一部分,主要用于描述JavaBean的属性(property),这些属性通常通过getter和setter方法来访问,如果一个 JavaBean 没有暴露 getset 方法,那么就无法通过PropertyDescriptor来修改属性值