首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

(转)研讨代理模式与Java反射机制的应用

2012-10-06 
(转)探讨代理模式与Java反射机制的应用代理模式,相信大多数人都非常熟悉,常见的实现方式是通过公共接口的

(转)探讨代理模式与Java反射机制的应用

代理模式,相信大多数人都非常熟悉,常见的实现方式是通过公共接口的方式,让我们的目标类和代理类实现同一接口,在代理类中调用目标类对象的方法。具体请看我另一个博客中的文章:Java的代理模式(通过公共接口实现) 。通过接口的方式,有个不好的地方,就是对每个目标类都要写一对与之相对应的接口和代理类,如果业务类很多,就是非常繁锁的工作了。

?

而加入反射机制的代理模式,可实现一个公共的代理类,省去我们不少功夫。Java的java.lang.reflect包及其子包中提供了Class、Method、Annotation等有用的类。下面,写个方法代理的类MethodProxy,实现动态地调用对象的方法。

?

    import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;/** * 方法代理类 * @author rongxinhua * */public class MethodProxy {private Class clazz;//对象所属的类private Object target;//目标对象private Method method;//目标方法private Object[] params;//参数数组@SuppressWarnings("unchecked")public MethodProxy(Object target, String methodName, Object ... params) {rebindTarget(target, methodName, params);//设置目标对象与方法}/** * 重新设置目标对象与方法 * @param target * @param methodName * @param params */public void rebindTarget(Object target, String methodName, Object ... params) {this.target = target;this.clazz = target.getClass();rebindMethod(methodName, params);//设置目标方法}/** * 重新设置目标方法 * @param methodName * @param params */public void rebindMethod(String methodName, Object ...params) {this.params = params;int paramLength = params.length;Class[] paramTypes = new Class[paramLength];for(int i = 0 ; i < paramLength ; i ++ ) {paramTypes[i] = params[i].getClass();}try {this.method = clazz.getMethod(methodName, paramTypes);} catch (SecurityException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();}}/** * 动态调用已绑定的方法 */public void doMethod() {try {this.method.invoke(target, params);} catch (IllegalArgumentException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}}

    ?

    这样就可以实现动态地调用某个对象的某个方法了,写个测试代码如下:

      public class Manager {public void say() {System.out.println("Nobody say nothing");}public void love(String boy, String girl) {System.out.println(boy + " love " + girl);}}

      ?

      ?我们通过代理类来调用Manager类中的say()和love()方法,测试代码如下:

        Manager man = new Manager();//目标对象MethodProxy proxy = new MethodProxy(man, "say");//方法代理对象proxy.doMethod();//调用被代理的方法proxy.rebindMethod("love", "Tom", "Marry");//重新绑定方法proxy.doMethod();//调用被代理的方法

        ?

        这样就实现了动态代理调用对象的方法,上面代码输出结果就不贴出来了。如果要设置前置通知和后置通知等功能,也很容易实现,只需在“proxy.doMethod()”代码处的前面和后面设置即行。


        扩展应用:我们在上面的MethodProxy类中加入以下方法:

          /** * 获取方法上的注解 * @param anClazz 注解类 * @return */public Annotation getAnnotation(Class anClazz) {return this.method.getAnnotation(anClazz);}

          ?

          这个方法用来读取方法上的注解(Annotation),有什么用呢?我们写一个注解来测试下。

            @Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)@interface Low {int boyAge();//男孩法定的谈恋爱年龄int girlAge();//女孩法定的谈恋爱年龄}

            我们要引进Annotation相关的类:

              import java.lang.annotation.Annotation;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;

              ?

              我们另外写一个测试用的业务类:

                public class LoveManager {@Low(boyAge=12, girlAge=10)public void beAbleToLove(Person boy, Person girl) {System.out.println(boy.getName() + " is able to love " + girl.getName());}}public class Person {private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}//getter方法略}

                ?

                接写上例中的proxy对象测试代码:

                  LoveManager loveManager = new LoveManager();Person boy = new Person("Tom", 13);Person girl = new Person("Marry", 10);proxy.rebindTarget(loveManager, "beAbleToLove", boy, girl);//重新绑定对象和方法Low low = (Low)proxy.getAnnotation(Low.class);if(boy.getAge() < low.boyAge()) {System.out.println(boy.getName() + "还不到法定年龄,不能谈恋爱!");} else if(girl.getAge() < low.girlAge()) {System.out.println(girl.getName() + "还不到法定年龄,不能谈恋爱!");} else {proxy.doMethod();}

                  ?

                  根据boy和girl的年龄大小,会相应地输出下列之一:

                  ?

                    Tom还不到法定年龄,不能谈恋爱!Marry还不到法定年龄,不能谈恋爱!Tom is able to love Marry

                    ?

                    这就实现了,通过Java的反射来读取Annotation的值,并根据Annotation的值,来处理业务数据有效性的判断,或者面向切面动态地注入对象,或者作日志、拦截器等等。这种用法在所多框架中都常常看到, 我们在开发自己的Java组件时,不妨也采用一下吧!

                    ?

                    原文地址:http://www.iteye.com/topic/629339

热点排行