在写如何使用java BeanUlits 之前需要清楚几件事情
1. 我们每次所定义的类,其实是实体,同时也被称作为JavaBean;
2. 为什么我们要使用BeanUlits这个框架
>在解决上面这个问题之前,我们得先搞清楚一件事情就是,在我们写javaWeb后端程序的时候,往往是拿到配置文件--xml格式的,而我们要做是将里面的数据对象变成我们的实例对象,也就是我们要做的事情就是将拿到的数据对象的属性复制到我们在程序中的实例化的对象属性,想做到这一步,其实是可以用反射的机制的。
•下面我来模拟一下这一过程
(1) 先在工程下新建一个txt文件来模拟一个配置的文件,如下图
(2) 接下来我们实现一个常见的需求 -- 写出一个工厂方法,根据文件的内容来返回对应的对象,并且要相应的属性值
1 package Introspect; 2 3 import java.io.BufferedReader; 4 import java.io.FileInputStream; 5 import java.io.FileNotFoundException; 6 import java.io.FileReader; 7 import java.io.IOException; 8 import java.lang.reflect.Constructor; 9 import java.lang.reflect.Field; 10 11 public class ReflectionToPruduceObj { 12 13 public static void main(String[] args) { 14 15 } 16 17 // 根据配置文件的内容来生产对象的对象,并且把对象的属性值也封装到生产的对象中去 18 public static Object getInstance() throws Exception{ 19 //step 1 : 用文件流来读取文件 20 BufferedReader bufferedReader = new BufferedReader(new FileReader("obj.txt")); 21 //step 2 : 读取配置文件获取完整的类名 22 String classname = bufferedReader.readLine(); 23 Class clazz = Class.forName(classname); 24 //step 3 : 通过Class对象获取无参的构造方法 25 Constructor constructor = clazz.getConstructor(); 26 //step 4 : 通过构造方法创建对象 27 Object o = constructor.newInstance(null); 28 //step 4 : 将对象的对属性值封装到创建的属性中去 29 String line = null; 30 while((line = bufferedReader.readLine())!= null){ 31 String[] dataStrings = line.split("=");// 这里是将属性的每一行按照等号左右来分开装如数组当中 32 // step 4.1 通过属性名来获取对应的Field对象 33 Field field = clazz.getDeclaredField(dataStrings[0]); 34 if(field.getType() == int.class){ 35 field.set(o, Integer.parseInt(dataStrings[1])); 36 }else{ 37 field.set(o, dataStrings[1]); 38 } 39 } 40 return o; 41 } 42 43 }
有上述的例子可以看出,以后我们开发一些工具框架的时候,就需要将数据封装到对象中去,底层的实现就是用的反射
从上面的代码可以看出,用反射来写是非常的麻烦的,所以sun公司就开发了一套工具叫做 内省--但是他其实也是一种封装好的反射
>用内省也是将配置文件对象的属性封装到新建的对象中去.
package Introspect; import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Method; import org.junit.Test; public class PeipertyDescrip { @Test public void testAllProperties() throws Exception { //introspector 这个就是内省类 BeanInfo beanInfo = Introspector.getBeanInfo(Member.class); PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors(); for (PropertyDescriptor propertyDescriptor : descriptors) { System.out.println(propertyDescriptor.getReadMethod()); } } @Test public void testPropertyDescriptor() throws Exception { Member member = new Member(); // 属性描述器 PropertyDescriptor descriptor = new PropertyDescriptor("id", Member.class); Method setIdMethod = descriptor.getWriteMethod(); // 其实就是得到这个属性的set方法 setIdMethod.invoke(member, 4); Method getIdMethod = descriptor.getReadMethod();// 这是获取属性的get方法 System.out.println(getIdMethod.invoke(member,null)); System.out.println(member); } }
由图可见,有了内省类之后,主要功能是能够得到类中的set与get方法,从而来对类的属性进行设置,然后还可以拥有一个属性描述器的数组来对得到属性的get与set的方法,但是其实我觉得这种方式跟反射并没有什么两样,所以它可以看作是一种变态的反射而已,因为反射是直接可以拿到属性Flied 来做文章,只不过是priavte的时候,要添加些方法,而内省是直接拿到类的get与set方法,对类进行设置,当让这前提是要新增属性描述器.
所以综上所看,这两种方法大同小异,但是都比较麻烦所以,apache公司就封装了内省这门技术,开发了beanutils这个工具包供我们使用,下面是使用方法
(1) 首先你的引入BeanUtils这个包,这个方法同junit一样,然后,就可以直接使用了
(2) 下面是我po出用BeanUtils的代码
package Introspect;
import java.lang.reflect.InvocationTargetException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.beanutils.ConvertUtils; import org.apache.commons.beanutils.Converter; public class UseBeanUtils { public static void main(String[] args) throws Exception { Member member = new Member(); String id = "01"; String name = "王倩楠"; String passWord = "1997"; String birthday = "1997-11-18"; ConvertUtils.register(new Converter() { public Object convert(Class type, Object value) { Date date = null; SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); try { date = dateFormat.parse((String) value); } catch (ParseException e) { e.printStackTrace(); } return date; } }, Date.class); BeanUtils.setProperty(member, "id", id); BeanUtils.setProperty(member, "name", name); BeanUtils.setProperty(member, "passWord", passWord); BeanUtils.setProperty(member, "birthday", birthday); System.err.println(member); } }
在这里要注意几点使用BeanUtils的事项:
首先,要清楚BeanUtils是对内省这门技术的封装,所以它的底层也是由得到get与set方法来实现的,所以你的类里面是必须要有这两种方法的
其次, Beanutils只能对基本数据类型和String类型来进行直接的设置,其余的java的一些封装的类,比如Date等,是需要引入转换器,ConvertUtils来注册一个转换器的,上面代码上也有,对于Date的转换器的注册,里面的转换器其实是一个接口,所以只要实现这个接口就可以直接使用,所以,我们直接写了一个内部类,来实现这个date的转换器,具体的实现方法,代码上都有体现。
现在来根据配置文件进行将对象的属性写入新创建的对象中就非常的方便了。