我们知道PropertyUtils类提供了动态获取/设置既存JavaBean类的属性,但是并不修改JavaBean类。
另一种动态属性访问的方式是希望表示动态计算的JavaBean属性集,而不是去编写实际的Java类来表示这些属性。
除了节省创建和维护单独的java类的工作之外,这个功能意味着可以可以处理动态决定的属性。(例如将SQL查询语句的结果作为JavaBeans来表示)。为了提供这个功能,BeanUtils提供了DynaBean接口以及关联的DynaClass接口。
DynaClass接口定义了特定一组DynaBeans支持的属性,这和java.lang.Class定义的被所有JavaBean类支持的属性集相同。例如,Employee类可以实现DynaBean接口,而不是标准的JavaBean,此时可以通过下面的方式来访问其属性:
//
Details depend on which
DynaBean
employee =
...;
//
DynaBean implementation you use
String
firstName = (String) employee.get("firstName");
Address
homeAddress = (Address) employee.get("address", "home");
Object
subordinate = employee.get("subordinate", 2);
由于DynaBean和DynaClass都是接口,所以多次被实现,在不同的应用场景以及以不同的方式。
BasicDynaBean和BasicDynaClass提供了基本的实现。
DynaProperty[] props = new DynaProperty[]{
new DynaProperty("address", java.util.Map.class),
new DynaProperty("subordinate", mypackage.Employee[].class),
new DynaProperty("firstName", String.class),
new DynaProperty("lastName", String.class)
};
BasicDynaClass dynaClass = new BasicDynaClass("employee", null,
props);
注意BasicDynaClass的dynaBeanClass参数可以设置为null,此时,dynaClass.getDynaBeanClass返回BasicDynaBean的Class。
接下来就可以使用newInstance方法来创建DynaClass实例,并进行填充初始值。
DynaBean
employee = dynaClass.newInstance();
employee.set("address", new HashMap());
employee.set("subordinate", new mypackage.Employee[0]);
employee.set("firstName", "Fred");
employee.set("lastName", "Flintstone");
此时可以将DynaBean作为第一个对象提供给PropertyUtils类的方法。
而在此过程中,并不需要创建独立的java源文件。
其中还有一些类:
ResultSetDynaClass专门用于封装SQL
SELECT语句的结果。但是ResultSet必须一致保持open的状态。这阻碍了在MVC结构(例如struts)中使用ResultSetDynaClass在model层和视图层之间的交互,因为无法确保ResultSet最后被关闭了。
RowSetDynaClass用于解决上述问题。当创建RowSetDynaClass时,底层的数据被拷贝到内存中的DynaBeans集合中。该方式的好处在于可以在创建之后就关闭ResultSet。缺点自然就是性能上的损失,因为要将数据放在内存中。
WrapDynaBean和WrapDynaClass提供了对标准JavaBeans的封装。
MyBean bean
= ...;
DynaBean
wrapper = new WrapDynaBean(bean);
String
firstName = wrapper.get("firstName");
Lazy
DynaBeans提供了以下的特性:添加属性,增长List/Array长度,List/Array实例化,Map实例化,Bean实例化。Lazy
DynaBeans包含以下几个类:
LazyDynaBean,LazyDynaList,LazyDynaMap,LazyDynaClass。