Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 288|回复: 0

[设计模式学习]探讨代理模式与Java反射机制的应用

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-11-4 00:01:11 | 显示全部楼层 |阅读模式
    代理模式,相信大多数人都非常熟悉,常见的实现方式是通过公共接口的方式,让我们的目标类和代理类实现同一接口,在代理类中调用目标类对象的方法。具体请看我另一个博客中的文章: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 = params.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();
                    }
            }
    }[/code] 这样就可以实现动态地调用某个对象的某个方法了,写个测试代码如下: 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);
            }
           
    }[/code]  我们通过代理类来调用Manager类中的say()和love()方法,测试代码如下:                 Manager man = new Manager();        //目标对象
                    MethodProxy proxy = new MethodProxy(man, "say");        //方法代理对象
                    proxy.doMethod();        //调用被代理的方法
                    proxy.rebindMethod("love", "Tom", "Marry");        //重新绑定方法
                    proxy.doMethod();        //调用被代理的方法[/code] 这样就实现了动态代理调用对象的方法,上面代码输出结果就不贴出来了。如果要设置前置通知和后置通知等功能,也很容易实现,只需在“proxy.doMethod()”代码处的前面和后面设置即行。
    扩展应用:我们在上面的MethodProxy类中加入以下方法:         /**
             * 获取方法上的注解
             * @param anClazz 注解类
             * @return
             */
            public Annotation getAnnotation(Class anClazz) {
                    return this.method.getAnnotation(anClazz);
            }[/code] 这个方法用来读取方法上的注解(Annotation),有什么用呢?我们写一个注解来测试下。 @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    @interface Low {
            int boyAge();        //男孩法定的谈恋爱年龄
            int girlAge();        //女孩法定的谈恋爱年龄
    }
                      [/code] 我们要引进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;[/code] 我们另外写一个测试用的业务类: 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方法略
    }[/code] 接写上例中的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();
    }[/code] 根据boy和girl的年龄大小,会相应地输出下列之一: Tom还不到法定年龄,不能谈恋爱!
    Marry还不到法定年龄,不能谈恋爱!
    Tom is able to love Marry[/code]    这就实现了,通过Java的反射来读取Annotation的值,并根据Annotation的值,来处理业务数据有效性的判断,或者面向切面动态地注入对象,或者作日志、拦截器等等。这种用法在所多框架中都常常看到, 我们在开发自己的Java组件时,不妨也采用一下吧!

      
      
       
       

         
       

         
       
      
    复制代码
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-25 14:25 , Processed in 0.319007 second(s), 36 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表