反射——reflect,也称为类的解剖机制。在学习完servlet、jsp后,一般,请求信息的传递都是通过四大作用域来实现再结合EL表达式去实现bean的field字段值的解析。本文使用反射来实现EL表达式的解析过程。
说到反射去模拟EL表达式的解析过程,也就是通过请求参数的内容去提取信息,然后对有效信息部分进行分析,最终得到我们想要的属性字段field以及拼接出po类的相关字段的set或get方法,再通过反射机制去解析bean的setXxx和getXxx成员方法的过程。
下面就通过简单的实例来模拟一下:
首先,构建Po类User[User.java]
package com.jjyy.beanparse.po;
public class User {
private String name;
private String phone;
private Integer age;
private Department department;
public User() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
}
然后,就是实现对Bean的解析操作的方法,写一个ParseBean的类,专门处理解析操作——ParserBean.java
package com.jjyy.beanparse.util;
import java.lang.reflect.Method;
/**
* //利用反射机制实现bean的解析
* @author Administrator--jiangyu 2014-8-15
* 下午09:43:50
*/
public class ParseBean {
/**
* 拼接出方法名
* @param pre 方法的前缀 一般取属性的值为“get”
* @param field bean中的属性字段名
* @return
*/
public static String generateMethodName(String pre,String field){
//获得属性字段名 xxx 转为Xxx
String prop = Character.toUpperCase(field.charAt(0))+field.substring(1);
//拼接出方法名
String methodName = pre+prop;
return methodName;
}
/**
* 解析请求信息 获取属性字段的值
* @param bean 传入的要解析的bean对象
* @param expr 要解析的请求信息
* @return 返回取到对应字段的值
*/
public static Object parse(Object bean,String expr){
//获得bean的一个
Class beanClass = bean.getClass();
Method method = null;
Object value = null;
try {
//通过放射机制 获得方法 并执行[由于get访问器没有参数,所以直接传入null]
method = beanClass.getMethod(generateMethodName("get",expr),null);
//调用get方法 获得值
value = method.invoke(bean, null);
} catch (Exception e) {
e.printStackTrace();
}
return value;
}
/**
* @param bean 传入的要解析的bean对象
* @param expr 要解析的请求信息
* @return 属性字段的名称
*/
public static Object parseRequestString(Object bean,String expr){
//一般属性都是以xxx.xxx的方式来获取的,所以对其进行切割
String keys[] = expr.split("\\.");
Object value = null;
value = parse(bean, keys[1]);
return value;
}
最后,通过简单的测试,运用一下上面的方法:
TestParse.java
import com.jjyy.beanparse.po.User;
import com.jjyy.beanparse.util.ParseBean;
public class TestParse {
public static void main(String[] args) {
User user = new User();
user.setName("jjyy");
user.setPhone("1552304");
user.setAge(22);
System.out.println(ParseBean.parseRequestString(user,"user.name"));
System.out.println(ParseBean.parseRequestString(user,"user.phone"));
System.out.println(ParseBean.parseRequestString(user,"user.age"));
}
结果为:
jjyy
1552304
22
通过以上的测试,基本上是实现了解析的过程。但是,有时候我们的请求信息中不是xxx.xxx形式,而是xxx.xxx.xxx形式,也就是说,我们涉及到的是多表之间的映射,有关联,上面的解析过程就有问题了。所以为了解决多层次的引用,我们可以对上面的parseRequestString方法做一点改进:
首先,为了引出xxx.xxx.xxx的引用形式,需要在建一个Po类,例如:Department
Department.java
package com.jjyy.beanparse.po;
public class Department {
private String name;
private String add;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAdd() {
return add;
}
public void setAdd(String add) {
this.add = add;
}
}
同理,User.java中也要将Department作为一个属性字段,其实前面已经加入了。下面是改进后的解析方法:
/**
* @param bean 传入的要解析的bean对象
* @param expr 要解析的请求信息
* @return 属性字段的名称
*/
public static Object parseRequestString2(Object bean,String expr){
//一般属性都是以xxx.xxx的方式来获取的,所以对其进行切割
String keys[] = expr.split("\\.");
Object value = null;
//递归parse
for (int i = 1; i < keys.length; i++) {
value = parse(bean, keys[i]);
bean = value;//处理xxx.xxx.xxx的形式的请求,比如"user.department.name"
}
return value;
}
然后,我们再测试一下,该方法是不是可行。
package com.jjyy.beanparse.test;
import com.jjyy.beanparse.po.Department;
import com.jjyy.beanparse.po.User;
import com.jjyy.beanparse.util.ParseBean;
public class TestParse {
public static void main(String[] args) {
User user = new User();
user.setName("jjyy");
user.setPhone("1552304");
user.setAge(22);
System.out.println(ParseBean.parseRequestString(user,"user.name"));
System.out.println(ParseBean.parseRequestString(user,"user.phone"));
System.out.println(ParseBean.parseRequestString(user,"user.age"));
Department department = new Department();
department.setName("科技部");
department.setAdd("北京");
user.setDepartment(department);
System.out.println(ParseBean.parseRequestString2(user, "user.department.name"));
System.out.println(ParseBean.parseRequestString2(user, "user.department.add"));
}
}
执行之后的结果为:
jjyy
1552304
22
科技部
北京
通过以上模拟EL表达式的过程,我们可以知道一种表达是内部的实现机制基本上是通过反射来实现的。所谓的站在反射的高度去看待java中的一切,或许会有一样的发现。
本人由于在开发实战经验等方面不足,如果有什么不到位的地方,恳请各位前辈出来指点指点。
如果读者对反射机制感兴趣或者不是很清楚,可以看一下本人转载的一篇关于反射的讲解博文。