这是我参与8月更文挑战的第2天,活动详情查看:8月更文挑战
1、什么是内省
内省(Introspector) 是Java 语言对 JavaBean 类属性、事件的一种缺省处理方法。
JavaBean是一种特殊的类,主要用于传递数据信息,这种类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。如果在两个模块之间传递信息,可以将信息封装进JavaBean中,这种对象称为“值对象”(Value Object),或“VO”。方法比较少。这些信息储存在类的私有变量中,通过set()、get()获得。
它的底层实现还是Java的反射。
2、JDK内省类库
2.1、Introspector类
将JavaBean中的属性封装起来进行操作。程序把一个类当做JavaBean来看,就是调用Introspector.getBeanInfo()方法
@Test
public void test1() throws IntrospectionException {
//获取 User Bean 信息
BeanInfo userBeanInfo = Introspector.getBeanInfo(User.class);
//属性描述
PropertyDescriptor[] propertyDescriptors = userBeanInfo.getPropertyDescriptors();
System.out.println("属性描述:");
Stream.of(propertyDescriptors).forEach(System.out::println);
//方法描述
System.out.println("方法描述:");
MethodDescriptor[] methodDescriptors = userBeanInfo.getMethodDescriptors();
Stream.of(methodDescriptors).forEach(System.out::println);
//事件描述
System.out.println("事件描述:");
EventSetDescriptor[] eventSetDescriptors = userBeanInfo.getEventSetDescriptors();
Stream.of(eventSetDescriptors).forEach(System.out::println);
}
2.2、PropertyDescriptor类
PropertyDescriptor类表示JavaBean类通过存储器导出一个属性。主要方法:
- getPropertyType(),获得属性的Class对象;
- getReadMethod(),获得用于读取属性值的方法;getWriteMethod(),获得用于写入属性值的方法;
- hashCode(),获取对象的哈希值;
- setReadMethod(Method readMethod),设置用于读取属性值的方法;
- setWriteMethod(Method writeMethod),设置用于写入属性值的方法。
2.3、属性变化类
java.beans 包中也提供了相应实现:
PropertyChangeSupportVetoableChangeSupport支持约束属性的bean使用的实用程序类,比如判断新值不为空
2.4、代码实战
假设有类UserInfo:
public class UserInfo {
private String userName;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
新建了一个测试类,分别使用PropertyDescriptor、Introspector、还有Spring对内省的封装类BeanWrapper。
测试类如下:
public class IntrospectorTest {
@Test
public void test() throws Exception {
UserInfo userInfo = new UserInfo();
userInfo.setUserName("zhang san");
// 使用PropertyDescriptor
setProperty(userInfo, "userName");
// 使用Introspector
setPropertyUseIntrospector(userInfo, "userName");
// 使用Spring
setPropertyUseSpring(userInfo, "userName");
}
public static void setPropertyUseSpring(UserInfo userInfo, String userName) {
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(userInfo);
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add(userName,"使用spring");
bw.setPropertyValues(pvs);
System.out.println("set userName:" + userInfo.getUserName());
}
public static void setProperty(UserInfo userInfo, String userName) throws Exception {
PropertyDescriptor propDesc = new PropertyDescriptor(userName, UserInfo.class);
Method methodSetUserName = propDesc.getWriteMethod();
methodSetUserName.invoke(userInfo, "使用PropertyDescriptor");
System.out.println("set userName:" + userInfo.getUserName());
}
public static void setPropertyUseIntrospector(UserInfo userInfo, String userName) throws Exception {
BeanInfo beanInfo= Introspector.getBeanInfo(UserInfo.class);
Arrays.stream(beanInfo.getPropertyDescriptors())
.filter(x->x.getName().equals(userName))
.findFirst()
.get()
.getWriteMethod().invoke(userInfo,"使用Introspector");
System.out.println("set userName:" + userInfo.getUserName());
}
}
输出为:
set userName:使用PropertyDescriptor
set userName:使用Introspector
set userName:使用spring
Java中通过java.beans.Introspector来进行内省操作。常用的内省操作主要有下面这些,当然还有其它的附加类型。
3、总结
Java反射是在运行时获取一个类的所有信息,可以操纵类的字段、方法、构造器等,功能非常强大。而内省其实就是反射的一个子集,基于反射实现。专门操作JavaBean的,只关注于JavaBean的属性、方法、事件的一些属性。