Java内省用法_java内省机制及PropertyUtils使用方法

反射

相对而言,反射比内省更容易理解一点。用一句比较白的话来概括,反射就是让你可以通过名称来得到对象(类,属性,方法)的技术。例如我们可以通过类

名来生成一个类的实例;知道了方法名,就可以调用这个方法;知道了属性名就可以访问这个属性的值,还是写两个例子让大家更直观的了解反射的使用方法:

//通过类名来构造一个类的实例

ClassClasscls_str=Class.forName("java.lang.String");

//上面这句很眼熟,因为使用过JDBC访问数据库的人都用过J

Objectstr=cls_str.newInstance();

//相当于Stringstr=newString();

//通过方法名来调用一个方法

StringmethodName="length";

Methodm=cls_str.getMethod(methodName,null);

System.out.println("lengthis"+m.invoke(str,null));

//相当于System.out.println(str.length());

上面的两个例子是比较常用方法。看到上面的例子就有人要发问了:为什么要这么麻烦呢?本来一条语句就完成的事情干吗要整这么复杂?没错,在上面的例 子中确实没有必要这么麻烦。不过你想像这样一个应用程序,它支持动态的功能扩展,也就是说程序不重新启动但是可以自动加载新的功能,这个功能使用一个具体 类来表示。首先我们必须为这些功能定义一个接口类,然后我们要求所有扩展的功能类必须实现我指定的接口,这个规定了应用程序和可扩展功能之间的接口规则, 但是怎么动态加载呢?我们必须让应用程序知道要扩展的功能类的类名,比如是test.Func1,当我们把这个类名(字符串)告诉应用程序后,它就可以使 用我们第一个例子的方法来加载并启用新的功能。这就是类的反射,请问你有别的选择吗?

内省

内省是Java语言对Bean类属性、事件的一种缺省处理方法。例如类A中有属性name,那我们可以通过getName,setName来得到其 值或者设置新的值。通过getName/setName来访问name属性,这就是默认的规则。Java中提供了一套API用来访问某个属性的 getter/setter方法,通过这些API可以使你不需要了解这个规则,这些API存放于包java.beans中。

一般的做法是通过类Introspector来获取某个对象的BeanInfo信息,然后通过BeanInfo来获取属性的描述器 (PropertyDescriptor),通过这个属性描述器就可以获取某个属性对应的getter/setter方法,然后我们就可以通过反射机制来 调用这些方法。下面我们来看一个例子,这个例子把某个对象的所有属性名称和值都打印出来:

/*

*Createdon2004-6-29

*/

packagedemo;

importjava.beans.BeanInfo;

importjava.beans.Introspector;

importjava.beans.PropertyDescriptor;

publicclassIntrospectorDemo{

Stringname;

publicstaticvoidmain(String[]args)throwsException{

IntrospectorDemodemo=newIntrospectorDemo();

demo.setName("WinterLau");

//如果不想把父类的属性也列出来的话,

//那getBeanInfo的第二个参数填写父类的信息

BeanInfobi=Introspector.getBeanInfo(demo.getClass(),Object.class);

PropertyDescriptor[]props=bi.getPropertyDescriptors();

for(inti=0;i

System.out.println(props[i].getName()+"="+

props[i].getReadMethod().invoke(demo,null));

}

}

publicStringgetName(){

returnname;

}

publicvoidsetName(Stringname){

this.name=name;

}

}

Web开发框架Struts中的FormBean就是通过内省机制来将表单中的数据映射到类的属性上,因此要求FormBean的每个属性要有 getter/setter方法。但也并不总是这样,什么意思呢?就是说对一个Bean类来讲,我可以没有属性,但是只要有getter/setter方 法中的其中一个,那么Java的内省机制就会认为存在一个属性,比如类中有方法setMobile,那么就认为存在一个mobile的属性,这样可以方便 我们把Bean类通过一个接口来定义而不用去关心具体实现,不用去关心Bean中数据的存储。比如我们可以把所有的getter/setter方法放到接 口里定义,但是真正数据的存取则是在具体类中去实现,这样可提高系统的扩展性。

总结

将Java的反射以及内省应用到程序设计中去可以大大的提供程序的智能化和可扩展性。有很多项目都是采取这两种技术来实现其核心功能,例如我们前面 提到的Struts,还有用于处理XML文件的Digester项目,其实应该说几乎所有的项目都或多或少的采用这两种技术。在实际应用过程中二者要相互 结合方能发挥真正的智能化以及高度可扩展性。

三、缺点及优化

在web.xml中注册IntrospectorCleanupListener监听器以解决struts等框架可能产生的内存泄露问题

增加方式如下:

org.springframework.web.util.IntrospectorCleanupListener

org.springframework.web.util.IntrospectorCleanupListener

org.springframework.web.util.IntrospectorCleanupListener源代码中对其的解释如下:

Listener

that flushes the JDK's JavaBeans Introspector cache on web app

shutdown. Register this listener in your web.xml to guarantee proper

release of the web application class loader and its

loaded classes.

在Web应用程序关闭时IntrospectorCleanupListener将会刷新JDK的JavaBeans的Introspector缓存。在

你的web.xml中注册这个listener来确保Web应用程序的类加载器以及其加载的类正确的释放资源。

If

the JavaBeans Introspector has been used to analyze application classes,

the system-level Introspector cache will hold a hard reference to those

classes. Consequently, those classes and the

web application class loader will not be garbage-collected on web app

shutdown! This listener performs proper cleanup, to allow for garbage

collection to take effect.

如果JavaBeans的Introspector已被用来分析应用程序类,系统级的Introspector缓存将持有这些类的一

个硬引用。因此,这些类和Web应用程序的类加载器在Web应用程序关闭时将不会被垃圾收集器回收!而

IntrospectorCleanupListener则会对其进行适当的清理,已使其能够被垃圾收集器回收。

Unfortunately,

the only way to clean up the Introspector is to flush the entire cache,

as there is no way to specifically determine the application's classes

referenced there. This will remove

cached introspection results for all other applications in the server

too.

不幸的是,唯一能够清理Introspector的方法是刷新整个Introspector缓存,没有其他办法来确切指定应用程序所引用的类。这将删除所有其他应用程序在服务器的缓存的Introspector结果。

spring's

beans infrastructure within the application, as Spring's own

introspection results cache will immediately flush an analyzed class

from the JavaBeans Introspector cache and only hold a cache within the

application's own ClassLoader. Although Spring itself does not create

JDK Introspector leaks, note that this listener should nevertheless be

used in scenarios where the Spring framework

classes themselves reside in a 'common' ClassLoader (such as the system

ClassLoader). In such a scenario, this listener will properly clean up

Spring's introspection cache.

请注意,在使用Spring内部的bean机制时,不需要使用此监听器,因为Spring自己的introspection

results cache将会立即刷新被分析过的JavaBeans Introspector

cache,而仅仅会在应用程序自己的ClassLoader里面持有一个cache。虽然Spring本身不产生泄漏,注意,即使在Spring框架的

类本身驻留在一个“共同”类加载器(如系统的ClassLoader)的情况下,也仍然应该使用使用

IntrospectorCleanupListener。在这种情况下,这个IntrospectorCleanupListener将会妥善清理

Spring的introspection

cache。

Application

classes hardly ever need to use the JavaBeans Introspector directly, so

are normally not the cause of Introspector resource leaks. Rather, many

libraries and frameworks do not clean

up the Introspector: e.g. Struts and Quartz.

应用程序类,几乎不需要直接使用JavaBeans Introspector,所以,通常都不是Introspector resource造成内存泄露。相反,许多库和框架,不清理Introspector,例如: Struts和Quartz。

Note

that a single such Introspector leak will cause the entire web app class

loader to not get garbage collected! This has the consequence that you

will see all the application's static class

resources (like singletons) around after web app shutdown, which is not

the fault of those classes!

需要注意的是一个简单Introspector泄漏将会导致整个Web应用程序的类加载器不会被回收!这样做的结果,将会是在web应用程序关闭时,该应

用程序所有的静态类资源(比如:单实例对象)都没有得到释放。而导致内存泄露的根本原因其实并不是这些未被回收的类!

This listener should be registered as the first one in web.xml, before any application listeners

such as Spring's ContextLoaderListener. This allows the listener to take full effect at the right time of the lifecycle.

IntrospectorCleanupListener应该注册为web.xml中的第一个Listener,在任何其他

Listener之前注册,比如在Spring's

ContextLoaderListener注册之前,才能确保IntrospectorCleanupListener在Web应用的生命周期适当时机

生效。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值