内省(IntroSpector)
内省(IntroSpector)是Java语言对JavaBean 类属性、方法及事件的一种处理方法,只有符合JavaBean规则的类的成员才可以采用内省API进行操作.
其操作方式是通过Introspector的getBeanInfo方法获取BeanInfo对象,再得到属性描述器PropertyDecriptor后再进行各种操作。
PropertyDescriptor类表示JavaBean类通过存储器导出一个属性。主要方法:
1. getPropertyType(),获得属性的Class对象;
2. getReadMethod(),获得用于读取属性值的方法;
3. getWriteMethod(),获得用于写入属性值的方法;
4. hashCode(),获取对象的哈希值;
5. setReadMethod(Method readMethod),设置用于读取属性值的方法;
6. setWriteMethod(Method writeMethod),设置用于写入属性值的方法。
示例:
package com.example.springsource;
import java.beans.*;
import java.lang.reflect.Method;
/**
1).addField属性没有对应的get/set方法,则不能进行操作.
2).没有对应的missName属性,但是可以用getMissName()/setMissName方法,推测是去掉set前缀,然后取剩余部分.
* @author Taxz
* @version 1.0.0
* @ClassName IntrospectorExample.java
* @Description TODO
* @createTime 2020年06月16日 17:15:00
*/
public class IntrospectorExample {
public static void main (String[] args) throws Exception {
//获取保存Foo.class的属性,方法和事件的BeanInfo
BeanInfo beanInfo = Introspector.getBeanInfo(Foo.class);
Foo foo = new Foo();
foo.setName("foo");
foo.setGrade(1);
foo.setDetail("info....");
System.out.println("The foo created : " + foo);
BeanDescriptor bd = beanInfo.getBeanDescriptor();
System.out.println("Bean name: " + bd.getName());
System.out.println("Bean class: " + bd.getBeanClass());
//属性描述器
for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
System.out.println("----------");
System.out.println("属性name: " + pd.getName());
System.out.println("属性type: " + pd.getPropertyType());
if (pd.getPropertyType().isAssignableFrom(java.lang.String.class)) {
System.out.println("通过getReadMethod()方法获取value: " + pd.getReadMethod().invoke(foo));
pd.getWriteMethod().invoke(foo, pd.getName()+"2");
System.out.println("获取getWriteMethod()设置后的value: " + pd.getReadMethod().invoke(foo));
}
if (pd.getPropertyType().isAssignableFrom(java.lang.Integer.class)) {
System.out.println("通过getReadMethod()方法获取value: " + pd.getReadMethod().invoke(foo));
Integer value = (Integer) pd.getReadMethod().invoke(foo);
pd.getWriteMethod().invoke(foo, value+1);
System.out.println("获取getWriteMethod()设置后的value: " + pd.getReadMethod().invoke(foo));
}
}
}
public static class Foo {
private String name;
private Integer grade;
private String detail;
private String addField;
public String getMissName() {
return "getMissName";
}
public void setMissName(String missName) {
System.out.println(missName);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getGrade() {
return grade;
}
public void setGrade(Integer grade) {
this.grade = grade;
}
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail;
}
}
}
//--------------------执行结果
The foo created : com.example.springsource.IntrospectorExample$Foo@5d3411d
Bean name: IntrospectorExample$Foo
Bean class: class com.example.springsource.IntrospectorExample$Foo
----------
属性name: class
属性type: class java.lang.Class
----------
属性name: detail
属性type: class java.lang.String
通过getReadMethod()方法获取value: info....
获取getWriteMethod()设置后的value: detail2
----------
属性name: grade
属性type: class java.lang.Integer
通过getReadMethod()方法获取value: 1
获取getWriteMethod()设置后的value: 2
----------
属性name: missName
属性type: class java.lang.String
通过getReadMethod()方法获取value: getMissName
missName2
获取getWriteMethod()设置后的value: getMissName
----------
属性name: name
属性type: class java.lang.String
通过getReadMethod()方法获取value: foo
获取getWriteMethod()设置后的value: name2
反射(Reflect)
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
简单点说: 反射就是可以通过全类名来得到对象(类,属性,方法)的技术。例如我们可以通过类名来生成一个类的实例;可以获取方法名,调用这个方法;也可以获取属性名访问这个属性的值,示例可自行查看文档.
IntrospectorCleanupListener
在web.xml配置,
<!-- 解决java.beans.Introspector导致的内存泄漏的问题(必须放在listener第1个位置) -->
<listener>
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>
作用解释
JDK中的java.beans.Introspector类的用途是发现Java类是否符合JavaBean规范, 如果有的框架或程序用到了Introspector类,那么就会启用一个系统级别的缓存,此缓存会存放一些曾加载并分析过的JavaBean的引用。当Web服务器关闭时,由于此缓存中存放着这些JavaBean的引用,所以垃圾回收器无法回收Web容器中的JavaBean对象,最后导致内存变大。而org.springframework.web.util.IntrospectorCleanupListener就是专门用来处理Introspector内存泄漏问题的辅助类。IntrospectorCleanupListener会在
Web服务器停止时清理Introspector缓存,使那些Javabean能被垃圾回收器正确回收。Spring自身不会出现这种问题,因为Spring在加载并分析完一个类之后会马上刷新JavaBeans Introspector缓存,这就保证Spring中不会出现这种内存泄漏的问题。但有些程序和框架在使用了JavaBeans Introspector之后,没有进行清理工作(如 Quartz,Struts),最后导致内存泄漏.
有不足之处欢迎指正!