zoukankan      html  css  js  c++  java
  • Java动态代理模式 -- 保护代理

    意义

    将接口的调用统一到一个函数里处理,然后再去具体实例调用相应的方法,充当一个分发器的作用

    user -> handler -> method

    字典

    动态:指的是在程序运行时才创建代理类

    代理:与被代理类具有相同的属性,也就是被代理类有run方法,它也有run方法

    保护代理:限制接口类的某些方法给特定的对象使用

    Proxy类:Java反射包自带,其中newProxyInstance可以返回接口实现类的实例

    组成

    1.接口

    Person类:其中有name与score相关的方法

    自己本人可以修改名字但不能修改分数

    别人可以修改分数不能修改名字

    public interface PersonBean {
        String getName();
        void setName(String name);
    
        int getScore();
        void setScore(int score);
    }

    2.实现接口的类

    public class PersonBeanImpl implements PersonBean {
        private String name;
        private int score;
    
        public PersonBeanImpl (){
        }
    
        public PersonBeanImpl (String name,int score){
            this.name = name;
            this.score = score;
        }
    
        public String getName (){
            return name;
        }
    
        public void setName (String name){
            this.name = name;
        }
    
        public int getScore (){
            return score;
        }
    
        public void setScore (int score){
            this.score = score;
        }
    }

    3.实现InvocationHandler的handler类

      它的invoke方法利用反射,PersonBean的方法调用时会来调用invoke,因此可以在invoke方法体实现相应逻辑,

      实例中就是限定某些方法允许调用,某些方法会抛出异常

      3.1 自身handler:当创建这个handler实例时,就说明只能修改name不能修改score

    public class OwnInvocationHandler implements InvocationHandler {
        // 需要代理的对象
        private PersonBean personBean;
    
        OwnInvocationHandler (PersonBean personBean){
            this.personBean = personBean;
        }
    
        // 代理设置规则
        public Object invoke (Object proxy ,Method method, Object[] args) throws Throwable{
            String methodName = method.getName();
            // 自己不能设置自己的分数
            if ("setScore".equals(methodName)) {
                throw new IllegalAccessException("自己不能给自己打分");
            } else {
                return method.invoke(personBean, args);
            }
        }
    }

      3.2 他人handler:当创建这个handler实例时,就说明只能修改score不能修改name

    public class OtherInvocationHandler implements InvocationHandler {
        // 需要代理的对象
        private PersonBean personBean;
    
        OtherInvocationHandler (PersonBean personBean){
            this.personBean = personBean;
        }
    
        // 代理设置规则
        public Object invoke (Object proxy ,Method method, Object[] args) throws Throwable{
            String methodName = method.getName();
            // 不能修改别人的名字
            if ("setName".equals(methodName)) {
                throw new IllegalAccessException("不能修改别人的名字");
            } else {
                return method.invoke(personBean, args);
            }
        }
    }

    4.生产handler类的工厂

    通过Proxy的newProxyInstance获取PersonBean对象

    它的主要作用:将传入的personBean与指定的InvocationHandler绑定,当PersonBean调用方法时,会去InvocationHandler调用invoke方法

    public class ProxyFactory {
        /**
         * 获得 个人 代理
         * @param personBean
         * @return
         */
        public PersonBean getOwnerProxy(PersonBean personBean) {
            return (PersonBean)Proxy.newProxyInstance(personBean.getClass().getClassLoader(),
                    personBean.getClass().getInterfaces(),
                    new OwnInvocationHandler(personBean));
        }
    
        /**
         * 获得 其他人 代理
         * @param personBean
         * @return
         */
        public PersonBean getOtherProxy(PersonBean personBean) {
            return (PersonBean)Proxy.newProxyInstance(personBean.getClass().getClassLoader(),
                    personBean.getClass().getInterfaces(),
                    new OtherInvocationHandler(personBean));
        }
    }

    参考《Head First 设计模式》 -- P474

  • 相关阅读:
    c#委托总结
    架构研究一(autofac 注册路由 )
    Fedora20 和ubuntu 14.04 chrome标签中文乱码
    Fedora20 编译安装qemu-system
    NFS安装配置
    Mysql自动备份脚本
    Mysql性能调优(my.cnf参数篇)
    Mysql性能基本测试
    mysql编译安装主从复制
    Mysql 配置参数详解以及优化配置
  • 原文地址:https://www.cnblogs.com/ming-szu/p/9498416.html
Copyright © 2011-2022 走看看