【Java进阶】内省IntroSpector操作JavaBean和Apache-commons-dbutils对内省的使用
来源:互联网 发布:广电网络缴费 编辑:程序博客网 时间:2024/06/06 01:27
【Java进阶】内省IntroSpector操作JavaBean和Apache-commons-dbutils对内省的使用
内省IntroSpector操作JavaBean
介绍JavaBean
JavaBean是一种特殊的Java类,主要用于传递数据信息,这种Java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。
如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称之为值对象(Value Object,简称VO)。
这些信息在类中用私有字段来存储,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问,大家觉得这些方法的名称叫什么好呢?
怎么确定JavaBean的属性?
JavaBean的属性是根据其中的setter和getter方法来确定的,而不是根据其中的成员变量。
如果方法名为setId,就是设置id,至于你把它存到哪个变量上,用管吗?
如果方法名为getId,就是获取id,至于你从哪个变量上取,用管吗?
去掉set前缀,剩余部分就是属性名,如果剩余部分的第二个字母是小写的,则把剩余部分的首字母改成小写的。
setId的属性名,id
isLast的属性名,last
setCPU的属性名,CPU
getUPS的属性名,UPS
总之,一个类被当作JavaBean使用时,JavaBean的属性是根据方法名推断出来的,它根本看不到Java内部的成员变量。
public class Person{ private int x; public int getAge(){ return x; } public void setAge(int age) { this.x = age; } }
一个符合JavaBean特点的类可以当作普通类一样进行使用,但把它当JavaBean用肯定需要带来一些额外的好处,我们才会去了解和应用JavaBean。
好处如下:
- 在JavaEE开发中,经常要使用到JavaBean。很多环境就要求按JavaBean方式进行操作,别人都这么用和要求这么做,那你就遵守大家的约定。
- JDK中提供了对JavaBean进行操作的API,这套API称为内省。如果要你自己去通过getX方法来访问私有的x,则怎么做,有一定难度吧?用这套内省api操作JavaBean比用普通类的方式更方便。
IntroSpector示例
对JavaBean操作常用的类有PropertyDescriptor, IntroSpector, BeanInfo等。
定义JavaBean
package javaenhance.part02;import org.junit.Test;import java.beans.IntrospectionException;import java.beans.PropertyDescriptor;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;/** * description: * * @author liyazhou * @since 2017-08-12 12:39 */// 定义JavaBeanclass Person{ private int age; public Person(){} public Person(int age){ this.age = age; } public int getAge(){ return age; } public void setAge(int age){ this.age = age; }}
使用PropertyDescriptor操作JavaBean
public class IntroSepctorTest { // 不使用getter方法情况下,通过JavaBean对象、属性名称和新的属性值,为JavaBean设置新的属性 public void setProperty(Object obj, String propertyName, Object newValue) throws Exception { // 属性描述符,根据属性名称和字节码获取到该属性的描述符 PropertyDescriptor pd = new PropertyDescriptor(propertyName, obj.getClass()); // 通过属性描述符,获取到该属性的写方法,也就是setter方法 Method setter = pd.getWriteMethod(); // invoke该属性的写方法Method setter.invoke(obj, newValue); } // 不使用getter方法情况下,通过JavaBean对象、属性名称,获得JavaBean的属性值 public Object getProperty(Object obj, String propertyName) throws Exception { // 属性描述符,根据属性名称和字节码获取到该属性的描述符 PropertyDescriptor pd = new PropertyDescriptor(propertyName, obj.getClass()); // 通过属性描述符,获取到该属性的读方法,也就是getter方法 Method getter = pd.getReadMethod(); // invoke该属性的读方法Method return getter.invoke(obj); } @Test public void propertyTest() throws Exception { Person p = new Person(12); String propertyName = "age"; Object retVal = getProperty(p, propertyName); System.out.println(propertyName + " = " + retVal); setProperty(p, propertyName, 22); System.out.println(propertyName + " = " + p.getAge()); }}
执行结果如下:
age = 12age = 22
此处,仅仅是抛砖引玉,大家可以通过查看java.beans.PropertyDescriptor学习更多的关于内省的知识。
DbUtils对内省的使用
之前看过Apache commons DbUtils的源码,记得有一段关于内省的源码,现在贴出一段,看看大神们怎么运用内省技术的。
源码分析
下面的这段代码在 org.apache.commons.dbutils.AbstractQueryRunner 这个类中。其中的中文部分,是自己的解释,如有问题,欢迎留言指正。
/** * Fill the <code>PreparedStatement</code> replacement parameters with the * given object's bean property values. * * @param stmt * PreparedStatement to fill * @param bean * A JavaBean object * @param propertyNames * An ordered array of property names (these should match the * getters/setters); this gives the order to insert values in the * statement * @throws SQLException * If a database access error occurs */ public void fillStatementWithBean(PreparedStatement stmt, Object bean, String... propertyNames) throws SQLException { PropertyDescriptor[] descriptors; try { // 通过bean的字节码获取到所有属性的描述符,是以数组形式返回的 descriptors = Introspector.getBeanInfo(bean.getClass()) .getPropertyDescriptors(); } catch (IntrospectionException e) { throw new RuntimeException("Couldn't introspect bean " + bean.getClass().toString(), e); } // 下面操作为了对属性描述符排序,以实现属性描述和属性的名称相对应 // 两层for循环,可见通用类的程序是有性能高代价的 // 总之,要权衡代码的复用性和性能的问题了 PropertyDescriptor[] sorted = new PropertyDescriptor[propertyNames.length]; for (int i = 0; i < propertyNames.length; i++) { // 获取一个属性名称 String propertyName = propertyNames[i]; if (propertyName == null) { throw new NullPointerException("propertyName can't be null: " + i); } boolean found = false; // 查找上面属性名称对应的属性描述符 for (int j = 0; j < descriptors.length; j++) { PropertyDescriptor descriptor = descriptors[j]; if (propertyName.equals(descriptor.getName())) { sorted[i] = descriptor; found = true; break; } } if (!found) { // 如果没有发现该属性对应的属性描述符,则抛出异常 throw new RuntimeException("Couldn't find bean property: " + bean.getClass() + " " + propertyName); } } fillStatementWithBean(stmt, bean, sorted); }
另一个方法
public void fillStatementWithBean(PreparedStatement stmt, Object bean, PropertyDescriptor[] properties) throws SQLException { Object[] params = new Object[properties.length]; for (int i = 0; i < properties.length; i++) { PropertyDescriptor property = properties[i]; Object value = null; Method method = property.getReadMethod(); if (method == null) { throw new RuntimeException("No read method for bean property " + bean.getClass() + " " + property.getName()); } try { // 为了获取属性的值 value = method.invoke(bean, new Object[0]); } catch (InvocationTargetException e) { throw new RuntimeException("Couldn't invoke method: " + method, e); } catch (IllegalArgumentException e) { throw new RuntimeException( "Couldn't invoke method with 0 arguments: " + method, e); } catch (IllegalAccessException e) { throw new RuntimeException("Couldn't invoke method: " + method, e); } params[i] = value; } fillStatement(stmt, params); }
能不能优化以上的程序
以上两个函数的目的就是,根据属性的名称和JavaBean获取到对应的属性值,它要求属性值跟属性名称的顺序性。
为了对属性描述符排序,以实现属性描述和属性的名称相对应,所以源代码中使用了两层for循环实现的。
个人认为这部分是存在优化空间的,可以使用下面的这种方式获取到属性名称对应的属性的值,而不需要循环操作。
// 不使用getter方法情况下,通过JavaBean对象、属性名称,获得JavaBean的属性值 public Object getProperty(Object obj, String propertyName) throws Exception { PropertyDescriptor pd = new PropertyDescriptor(propertyName, obj.getClass()); Method getter = pd.getReadMethod(); return getter.invoke(obj); }
参考
Apache commons dbutils源代码
《Java基础强化教程-张孝祥》
- 【Java进阶】内省IntroSpector操作JavaBean和Apache-commons-dbutils对内省的使用
- 通过PropertyDescriptor和Introspector对JavaBean的简单内省操作
- 【内省】introspector操作JavaBean
- JavaBean和内省 IntroSpector
- 内省(introspector)和javabean
- 内省(Introspector)操作JavaBean的属性
- 内省(Introspector)操作JavaBean的属性
- 内省(Introspector)操作JavaBean的属性
- JAVA内省JavaBean(Introspector、BeanInfo和PropertyDescriptor)
- java基础加强--JavaBean和内省Introspector
- 对javabean的简单内省和复杂内省操作
- Java 对JavaBean的简单内省操作
- Java的内省(Introspector)操作
- 内省IntroSpector与JavaBean
- 内省(Introspector) — JavaBean
- JavaBean内省:认识JavaBean与内省、对JavaBean的内省操作、Beanutils工具包
- java基础之内省(Introspector)操作javabean属性的理解(主要用于开发框架)
- Java高新技术之JavaBean(内省 IntroSpector)
- spring事物注意事项
- 【平衡二叉树】leetcode 110. Balanced Binary Tree
- zoj 1108 FatMouse's Speed 基础dp
- 士兵杀敌(二)
- java网络编程—NIO与Netty(三)
- 【Java进阶】内省IntroSpector操作JavaBean和Apache-commons-dbutils对内省的使用
- About 日历
- 聊一聊容器如何自适应高度和居于居中。
- Noip2013 Day1 T2 火柴排队(归并排序/树状数组 求逆序对)
- PAT-L1-027. 出租
- Andrew NG 机器学习 笔记-week1-单变量线性回归
- advanceFSM
- mysql中文乱码原因分析
- EasyUI的icon图标的种类