代理模式

1 静态代理

1、角色分析

  • 抽象角色:一般会使用接口或者抽象类来解决。
  • 真实角色:被代理的角色。
  • 代理角色:代理真实角色,一般会做一些附属操作。
  • 客户:访问代理对象的人。

2、好处

  • 可以使真实角色的操作更加纯粹,不用去关注一些公共的业务。
  • 公共业务交给代理角色,实现分工。
  • 公共业务发生扩展的时候,方便集中管理。

3、缺点

  • 一个真实角色就会产生一个代理角色,代码量翻倍,开发效率降低。

4、代码示例

  • 接口

    package proxy;
    
    /**
     * 租房
     */
    public interface Rent {
       void rent();
    }
  • 真实角色

    package proxy;
    
    /**
     * 房东
     */
    public class Host implements Rent {
       @Override
       public void rent() {
           System.out.println("房东要出租房子!");
       }
    }
  • 代理角色

    package proxy;
    
    public class Proxy implements Rent {
        private Host host;
    
        public Proxy() {
        }
    
        public Proxy(Host host) {
            this.host = host;
        }
    
        @Override
        public void rent() {
            seeHouse();
            host.rent();
            hetong();
            fare();
        }
    
        /**
         * 看房
         */
        public void seeHouse() {
            System.out.println("中介带你看房");
        }
    
        /**
         * 收中介费
         */
        public void fare() {
            System.out.println("收中介费");
        }
    
        /**
         * 签合同
         */
        public void hetong() {
            System.out.println("签合同");
        }
    }
  • 客户

    package proxy;
    
    import org.junit.Test;
    
    /**
     * 房客
     */
    public class Client {
       @Test
       public void test() {
           // 1、房东
           Host host = new Host();
           // 2、房东找中介代理
           Proxy proxy = new Proxy(host);
           // 3、代理出租房子,可以进行额外看房、签合同等操作
           proxy.rent();
       }
    }

5、静态代理与AOP

  • UserService

    package proxy.demo02;
    
    public interface UserService {
        void add();
        void delete();
        void update();
        void query();
    }
  • UserServiceImpl

    package proxy.demo02;
    
    /**
     * 真实对象
     */
    public class UserServiceImpl implements UserService {
       @Override
       public void add() {
           System.out.println("增加了一个用户");
       }
    
       @Override
       public void delete() {
           System.out.println("删除了一个用户");
       }
    
       @Override
       public void update() {
           System.out.println("修改了一个用户");
       }
    
       @Override
       public void query() {
           System.out.println("查询了一个用户");
       }
    }
  • UserServiceProxy

    package proxy.demo02;
    
    public class UserServiceProxy implements UserService {
        private UserServiceImpl userService;
    
        public void setUserService(UserServiceImpl userService) {
            this.userService = userService;
        }
    
        @Override
        public void add() {
            log("add");
            userService.add();
        }
    
        @Override
        public void delete() {
            log("delete");
            userService.delete();
        }
    
        @Override
        public void update() {
            log("update");
            userService.update();
        }
    
        @Override
        public void query() {
            log("query");
            userService.query();
        }
    
        public void log(String msg) {
            System.out.println("[日志]:使用了" + msg + "方法");
        }
    }
  • Client

    package proxy.demo02;
    
    import org.junit.Test;
    
    public class Client {
        @Test
        public void test() {
            UserServiceImpl userService = new UserServiceImpl();
            UserServiceProxy proxy = new UserServiceProxy();
            proxy.setUserService(userService);
            proxy.add();
        }
    }

2 动态代理

1、角色分析

  • 动态代理的角色与静态代理相同。
  • 动态代理的代理类是动态生成的,不是直接写好的!

2、分类

  • 基于接口:JDK动态代理。
  • 基于类:cglib。
  • Java字节码实现:Javasist(JBoss服务器)。

3、两个重要的类

  • InvocationHandler
  • Proxy

4、InvocationHandler

  • 代理实例的调用处理程序实现的接口。
  • 每个代理实例都有一个关联的调用处理程序,当在代理实例上调用方法时,方法调用将被编码并分派到其调用处理程序的invoke方法。
  package java.lang.reflect;

  public interface InvocationHandler {
      public Object invoke(Object proxy, Method method, Object[] args)
          throws Throwable;
  }

5、Proxy

  • 提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。
  InvocationHandler handler = new MyInvocationHandler(...);
  Foo f = (Foo)Proxy.newProxyInstance(Foo.class.getClassLoader(),
                                      new Class<?>[]{Foo.class},
                                      handler);

6、代码示例

  • Rent

    package proxy.demo03;
    
    /**
     * 租房
     */
    public interface Rent {
       void rent();
       }
    }
  • ProxyInvocationHandler

    package proxy.demo03;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     * 使用这个类,自动生成代理类
     */
    public class ProxyInvocationHandler implements InvocationHandler {
       // 被代理的接口
       private Rent rent;
    
       public void setRent(Rent rent) {
           this.rent = rent;
       }
    
       /**
        * 生成代理对象
        */
       public Object getProxy() {
          return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                  rent.getClass().getInterfaces(),
                  this);
       }
    
       /**
        * 处理代理实例,并返回结果
        * @param proxy  代理对象
        * @param method 被代理类的方法
        * @param args   方法的参数
        * @return 方法返回值
        * @throws Throwable
        */
       @Override
       public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
          seeHouse();
          // 动态代理的本质,就是使用反射机制实现!
          Object result = method.invoke(rent, args);
          fare();
          return result;
       }
    
       public void seeHouse() {
           System.out.println("看房子");
       }
    
       public void fare() {
           System.out.println("收中介费");
       }
    }
  • Host

    package proxy.demo03;
    
    /**
     * 房东
     */
    public class Host implements Rent {
       @Override
       public void rent() {
           System.out.println("房东要出租房子!");
       }
    }
  • Client

    package proxy.demo03;
    
    import org.junit.Test;
    
    public class Client {
        @Test
        public void test() {
            // 1、真实角色
            Host host = new Host();
            // 2、获取代理角色
            ProxyInvocationHandler handler = new ProxyInvocationHandler();
            handler.setRent(host);
            Rent proxy = (Rent) handler.getProxy(); // 动态生成
            // 3、使用
            proxy.rent();
        }
    }

7、万能的动态代理类

    package proxy.demo04;

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;

    public class ProxyInvocationHandler implements InvocationHandler {
        private Object target;

        public void setTarget(Object target) {
            this.target = target;
        }

        public Object getProxy() {
            return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                    target.getClass().getInterfaces(),
                    this);
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object result = method.invoke(target, args);
            return result;
        }
    }

8、动态代理的好处

  • 包含所有静态代理的好处。
  • 一个动态代理类代理的是一个接口,一般就是对应的一类业务。
  • 一个动态代理类可以代理多个类,只要是实现了同一个接口即可。
全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务