属性访问 PropertyDescriptor

引出

反射访问一个类的属性,往往有如下代码:

1
2
3
Field aField = aClass.getDeclaredField("fieldA");
aField.setAccessible(true);
aField.set(aObj, aValue);

这段代码在Fortify漏洞扫描中会被标记为中危漏洞,因为setAccessible往往意味着越权。

所以对于一个属性,应该用它的getter/setter去获取。

PropertyDescriptor

java.beans包下面给出了一个类,就是用于描述、定义一个属性的读写方法,并提供了默认的访问方式,即(get|is/set)。所以规范的操作应该是:

1
2
Method setter = new PropertyDescriptor(aClass, "fieldA");
setter.invoke(aObj, aValue);

另外,想获取一个类中所有的PropertyDescriptor,可以用下述代码:

1
Introspector.getBeanInfo(aClass).getPropertyDescriptors();

不过既然用到反射,说明方法会比较通用,既然通用,那估计这类操作是大量的。

每次 new 一个会不会有性能问题,底层引用的Method是同一个?

当然是同一个,而且深入源码,Introspector给beanInfo的做了系统级的缓存,如果不刷新就一直存在,用完要调用方法Introspctor.flushFromCaches(aClass)去除缓存。否则内存泄漏。

Spring BeanUtils

spring 框架开发者意识到这一点,在工具包提供的BeanUtils里提供了类似的方法:

1
BeanUtils.getPropertyDescriptor(aClass, "fieldA");

上面的方法里spring自己另外给beanInfo做了缓存,并非系统级而是web应用级别(classLoader),这样随着应用关闭,缓存里的beanInfo也会自动失效。推荐使用上面的工具类进行操作。