代理模式之Java动态代理

 2022-08-28
原文地址:https://www.51cto.com/article/253625.html
  1. Overview

Java在java.lang.reflect包下,定义了自己的代理。利用这个包下的类,我们可以在运行时动态地创建一个代理类,实现一个或多个接口。并将方法的调用转发到你所指定的类。因为实际代理是在运行时创建的,所以称为:动态代理。

202208282104238561.png

Proxy:完全由java产生的,而且实现了完整的subject接口。

InvocationHandler:Proxy上的任何方法调用都会被传入此类,InvocationHandler控制对RealSubject的访问。

因为Java已经帮助我们创建了Proxy类,我们需要有办法告诉Proxy类你要做什么,我们不能像以前一样把代码写入到Proxy类中,因为Proxy类不是我们实现的。那么我们应该放在哪里?放在InvocationHandler类中,InvocationHandler类是响应代理的任何调用。我们可以吧InvocationHandler想成是代理收到方法调用后,请求做实际工作的对象。

  1. java.lang.reflect.InvocationHandler

被代理实例所实现的一个接口,内部只有一个invoke()方法,签名如下;

Java代码

     
       
      
        public Object invoke(Object proxy, Method method, Object[] args)   

当代理的方法被调用的时候,代理就会把这个调用转发给InvocationHandler,也就会调用它的invoke()方法。

  1. java.lang.reflect.Proxy

提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类,我们经常使用的静态方式是:

Java代码

     
       
      
        newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)  
  1. 示例:

情形:自己可以查看修改姓名性别,但是不能修改rate。他人可以查看姓名,性别以及修改rate,但是不能修改姓名性别。

4.1 定义一个接口:

Java代码

     
       
      
        public interface Person {      
      
                  
      
            String getName();      
      
                  
      
            String getGender();      
      
                  
      
            void setName(String name);      
      
                  
      
            void setGender(String gender);      
      
                  
      
            void setRate(int rate);      
      
                  
      
            int getRate();      
      
        }   

4.2 定义实现Person接口类

Java代码

     
       
      
        public class PersonImpl implements Person {      
      
        String name;      
      
             
      
        String gender;      
      
             
      
        String interests;      
      
             
      
        int rate;      
      
             
      
        public String getName() {      
      
            return name;      
      
        }      
      
             
      
        public void setName(String name) {      
      
            this.name = name;      
      
        }      
      
             
      
        public String getGender() {      
      
            return gender;      
      
        }      
      
             
      
        public void setGender(String gender) {      
      
            this.gender = gender;      
      
        }      
      
             
      
        public String getInterests() {      
      
            return interests;      
      
        }      
      
             
      
        public void setInterests(String interests) {      
      
            this.interests = interests;      
      
        }      
      
             
      
        public int getRate() {      
      
            return rate;      
      
        }      
      
             
      
        public void setRate(int rate) {      
      
            this.rate = rate;      
      
        }   

4.3 定义OwnerInvocationHandler类,表示如果为本人,则可以进行修改查看姓名性别。

Java代码

     
       
      
        public class OwnerInvocationHandler implements InvocationHandler{      
      
                  
      
            private Person personBean;      
      
                  
      
            public OwnerInvocationHandler(Person personBean){      
      
                this.personBean = personBean;      
      
            }      
      
                  
      
            @Override     
      
            public Object invoke(Object proxy, Method method, Object[] args)      
      
                    throws IllegalAccessException {      
      
                      
      
                try {      
      
                    if(method.getName().startsWith("get")){//如果方法名为get,就调用person类内的get相应方法      
      
             
      
                        return method.invoke(personBean, args);      
      
                    }else if(method.getName().equals("setRate")){ // 如果方法是setRate,则抛出异常      
      
                        throw new IllegalAccessException("access deny");      
      
                    }else if(method.getName().startsWith("set")){  //如果为set,就调用person类内的set相应方法      
      
                        return method.invoke(personBean, args);      
      
                    }else {      
      
                        System.out.println("non method invoke");      
      
                    }      
      
                } catch (InvocationTargetException e) {      
      
                    e.printStackTrace();      
      
                }      
      
                return null;       
      
                      
      
            }      
      
                  
      
        }    

4.4 定义NonInvocationHandler类,表示如果不为本人,则可以进行查看姓名性别和修改rate。

Java代码

     
       
      
        public class NonInvocationHandler implements InvocationHandler{      
      
            //      
      
            private Person person;      
      
                  
      
            public NonInvocationHandler(Person person){      
      
                this.person = person;      
      
            }      
      
             
      
            @Override     
      
            public Object invoke(Object proxy, Method method, Object[] args)      
      
                    throws Throwable {      
      
                if(method.getName().startsWith("setRate")){      
      
                    return method.invoke(person, args);      
      
                }else if (method.getName().startsWith("get")){      
      
                    return method.invoke(person, args);      
      
                } else {      
      
                    System.out.println("non method invoke");      
      
                    return null;      
      
                }      
      
            }      
      
                  
      
        }   

4.5 测试类MyDynamicProxy

Java代码

     
       
      
        public class MyDynamicProxy {      
      
             
      
        public Person getOwnerPersonBeanProxy(Person person){      
      
            return (Person)Proxy.newProxyInstance(person.getClass().getClassLoader(),       
      
                    person.getClass().getInterfaces(), new OwnerInvocationHandler(person));      
      
        }      
      
             
      
        public Person getNonPersonBeanProxy(Person person){      
      
            return (Person)Proxy.newProxyInstance(person.getClass().getClassLoader(),       
      
                    person.getClass().getInterfaces(), new NonInvocationHandler(person));      
      
        }      
      
             
      
        public static void main(String[] args) {      
      
            MyDynamicProxy mdp = new MyDynamicProxy();      
      
            mdp.test();      
      
                  
      
        }      
      
             
      
        public void test(){      
      
                        //      
      
            Person person = getPersonBeanFromDB1();      
      
            Person personProxy = getOwnerPersonBeanProxy(person);      
      
            System.out.println(personProxy.getName());       
      
            try {      
      
                personProxy.setRate(2);      
      
            } catch (Exception e) {      
      
                System.out.println("can not setRate");      
      
            }      
      
                         //      
      
            Person person1 = getPersonBeanFromDB1();      
      
            Person personProxy2 = getNonPersonBeanProxy(person1);      
      
            System.out.println(personProxy2.getName());      
      
            personProxy2.setRate(2);      
      
            System.out.println(personProxy2.getRate());      
      
        }      
      
             
      
        private Person getPersonBeanFromDB1(){      
      
            Person pb = new PersonImpl();      
      
            pb.setName("remy");      
      
            pb.setGender("girl");      
      
            pb.setRate(1);      
      
            return pb;      
      
        }   

输出结果:

Java代码

     
       
      
        remy      
      
        can not setRate      
      
        remy      
      
        2 

【编辑推荐】

  1. Java程序开发中代理技术的使用方法
  2. 浅谈Java中用动态代理类实现记忆功能
  3. 探讨Java代理模式与反射机制的实际应用