關(guān)于Java反射機(jī)制的一個(gè)實(shí)例
JSP的規(guī)范中,有個(gè)表達(dá)式語言(Expression Language, 簡稱EL),可以算是一個(gè)微型的語言,其中對request, page, session, application中預(yù)存的JavaBean對象的引用方式很是簡單。最近正好需要寫一個(gè)支持簡單EL的taglib,所以就研究了下Java反射機(jī)制,目前基本上實(shí)現(xiàn)了多級bean的屬性的訪問,經(jīng)測試,還是可以用的。如:
- public static void main(String[] args){
- UserBean bean = new UserBean();
- bean.setName("John Abruzzi");
- bean.setNick("Abruzzi");
- bean.setAge(24);
- AddressBean addr = new AddressBean();
- addr.setZip("0086");
- addr.setStreet("Bell Street #12");
- bean.setAddress(addr);
- System.out.println(BeanParser.doParse(bean, "bean.address.street"));
- System.out.println(BeanParser.doParse(bean, "bean.address.zip"));
- System.out.println(BeanParser.doParse(bean, "bean.name"));
- System.out.println(BeanParser.doParse(bean, "bean.nick"));
- System.out.println(BeanParser.doParse(bean, "bean.age"));
- }
需要可以輸出:
- Bell Street #12
- 0086
- John Abruzzi
- Abruzzi
- 24
反射,即由一個(gè)抽象的對象(如Object),取出這個(gè)具體對象的屬性或者方法(就EL中關(guān)于Bean的引用來說,這個(gè)定義已經(jīng)夠了)。在EL中,對一個(gè)Bean的某字段進(jìn)行引用,只需 ${bean.field},當(dāng)然,這個(gè)bean是已經(jīng)被set到容器中的,這就是Java反射機(jī)制。
我們從容器中取出以bean為名字的Object,通過Java反射機(jī)制知道它的真實(shí)類型,然后通過field以javabean規(guī)范拼出方法名,進(jìn)行調(diào)用,如果這個(gè)表達(dá)式是多級的,如${bean.field.field},其中第一個(gè)field本身就是一個(gè)bean對象,同樣需要遞歸的進(jìn)行解析。
大概原理就是這些了,看代碼吧:
現(xiàn)有一個(gè)UserBean, 其中的一個(gè)字段Address本身又是一個(gè)AddressBean。
- package elparser;
- public class AddressBean {
- private String street;
- private String zip;
- public String getZip() {
- return zip;
- }
- public void setZip(String zip) {
- this.zip = zip;
- }
- public String getStreet() {
- return street;
- }
- public void setStreet(String street) {
- this.street = street;
- }
- }
然后是UserBean
- package elparser;
- public class UserBean {
- private String name;
- private String nick;
- private AddressBean address;
- private int age;
- public int getAge(){
- return this.age;
- }
- public void setAge(int age){
- this.age = age;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getNick() {
- return nick;
- }
- public void setNick(String nick) {
- this.nick = nick;
- }
- public AddressBean getAddress() {
- return address;
- }
- public void setAddress(AddressBean address) {
- this.address = address;
- }
- }
Bean都是很簡單的,考慮到對基本類型的支持,所以在UserBean中加入一個(gè)int型的字段age
好了,看看怎么通過一個(gè)串和一個(gè)對象來取出其中的字段來:
- package elparser;
- import java.lang.reflect.Method;
- public class BeanParser {
- private static String getMethodName(String property, String prefix){
- String prop = Character.toUpperCase(property.charAt(0))+property.substring(1);
- String methodName = prefix + prop;
- return methodName;
- }
- private static Object parse(Object bean, String expr){
- Class beanClass = bean.getClass();
- Method method = null;
- Object result = null;
- try{
- //這兩步是關(guān)鍵,get方法不需要傳入?yún)?shù),所以只是new出兩個(gè)空數(shù)組傳入
- method = beanClass.getMethod(getMethodName(expr, "get"), new Class[]{});
- result = method.invoke(bean, new Object[]{});
- }catch(Exception e){
- System.out.println(e.getMessage());
- }
- return result;
- }
- public static Object doParse(Object bean, String expr){
- String keys[] = expr.split("\\.");
- Object obj = null;
- for(int i = 1; i < keys.length;i++){
- obj = parse(bean, keys[i]);
- bean = obj;
- }//遞歸parse
- return obj;
- }
- public static void main(String[] args){
- UserBean bean = new UserBean();
- bean.setName("John Abruzzi");
- bean.setNick("Abruzzi");
- bean.setAge(24);
- AddressBean addr = new AddressBean();
- addr.setZip("0086");
- addr.setStreet("Bell Street #12");
- bean.setAddress(addr);
- System.out.println(BeanParser.doParse(bean, "bean.address.street"));
- System.out.println(BeanParser.doParse(bean, "bean.address.zip"));
- System.out.println(BeanParser.doParse(bean, "bean.name"));
- System.out.println(BeanParser.doParse(bean, "bean.nick"));
- System.out.println(BeanParser.doParse(bean, "bean.age"));
- }
- }
代碼比較簡短,重要部分有注釋,應(yīng)該很容易理解。當(dāng)然這篇文章主要是關(guān)于Java的反射機(jī)制,如果需要對EL完全支持,可以使用JavaCC做一個(gè)簡單的分析器(Apache的commons中包含一個(gè)el的項(xiàng)目,就是用javacc寫的分析器)。
【編輯推薦】