Spring:(六) 代理模式

一、前言

  • 代理模式
    • 静态代理
    • 动态代理

二、静态代理

  1. 角色分析

    • 抽象角色 : 一般使用接口或者抽象类来实现
    • 真实角色 : 被代理的角色
    • 代理角色 : 代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作 .
    • 客户 : 使用代理角色来进行一些操作 .
  2. 实现(中介租房)

    1. Rent :抽象角色

      //抽象角色:租房
      public interface Rent {
          public void rent();
      }
      
    2. Host . java 即真实角色

      //真实角色: 房东,房东要出租房子
      public class Host implements Rent{
          public void rent() {
              System.out.println("房屋出租");
          }
      }
      
    3. Proxy . java 即代理角色

      //代理角色:中介
      public class Proxy implements Rent {
      
          private Host host;
          public Proxy() { }
          public Proxy(Host host) {
              this.host = host;
          }
      
          //租房
          public void rent(){
              seeHouse();
              host.rent();
              fare();
          }
          //看房
          public void seeHouse(){
              System.out.println("带房客看房");
          }
          //收中介费
          public void fare(){
              System.out.println("收中介费");
          }
      }
      
    4. Client . java 即客户

      //客户类,一般客户都会去找代理!
      public class Client {
          public static void main(String[] args) {
              //房东要租房
              Host host = new Host();
              //中介帮助房东
              Proxy proxy = new Proxy(host);
      
              //你去找中介!
              proxy.rent();
          }
      }
      

      静态代理的好处

      • 使得真实角色更加纯粹 . 不再去关注一些公共的事情
      • 公共的业务由代理来完成 . 实现了业务的分工 ,
      • 公共业务发生扩展时变得更加集中和方便 .

      缺点

      • 类多了 , 多了代理类 , 工作量变大了 . 开发效率降低 .
  3. 实现2(t用户增删改查)

    1.什么事

    //抽象角色:增删改查业务
    public interface UserService {
        void add();
        void delete();
        void update();
        void query();
    }
    
    1. 真实对象来完成这些增删改查操作

      //真实对象,完成增删改查操作的人
      public class UserServiceImpl implements UserService {
      
          public void add() {
              System.out.println("增加了一个用户");
          }
      
          public void delete() {
              System.out.println("删除了一个用户");
          }
      
          public void update() {
              System.out.println("更新了一个用户");
          }
      
          public void query() {
              System.out.println("查询了一个用户");
          }
      }
      
    2. 需要增加一个日志功能,怎么实现,找代理最方便

      //代理角色,在这里面增加日志的实现
      public class UserServiceProxy implements UserService {
          private UserServiceImpl userService;
      
          public void setUserService(UserServiceImpl userService) {
              this.userService = userService;
          }
      
          public void add() {
              log("add");
              userService.add();
          }
      
          public void delete() {
              log("delete");
              userService.delete();
          }
      
          public void update() {
              log("update");
              userService.update();
          }
      
          public void query() {
              log("query");
              userService.query();
          }
      
          public void log(String msg){
              System.out.println("执行了"+msg+"方法");
          }
      
      }
      
      1. 测试

        public class Client {
            public static void main(String[] args) {
                //真实业务
                UserServiceImpl userService = new UserServiceImpl();
                //代理类
                UserServiceProxy proxy = new UserServiceProxy();
                //使用代理类实现日志功能!
                proxy.setUserService(userService);
        
                proxy.add();
            }
        }
        

三、动态代理

  1. 简介
  • 动态代理的代理类是动态生成的 . 静态代理的代理类是我们提前写好的
  • 动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理
  • 基于接口的动态代理----JDK动态代理
  • 基于类的动态代理--cglib
  • 现在用的比较多的是 javasist 来生成动态代理

  1. JDK的动态代理需要了解两个类
  • 核心 : InvocationHandler 和 Proxy

  • InvocationHandler

    • InvocationHandler 是由代理实例的,调用处理程序实现的接口

    • 每个代理实例都有一个关联的调用处理程序,在代理实例上调用方法的时候,方法调用将被编码,并分派到其调用处理程序的invoke方法

    • Object invoke(Object proxy, 方法 method, Object[] args);
      //参数 
      //proxy - 调用该方法的代理实例 
      //method -所述方法对应于调用代理实例上的接口方法的实例。 方法对象的声明类将是该方法声明的接口,它可以是代理类继承该方法的代理接口的超级接口。 
      //args -包含的方法调用传递代理实例的参数值的对象的阵列,或null如果接口方法没有参数。 原始类型的参数包含在适当的原始包装器类的实例中,例如java.lang.Integer或java.lang.Boolean 。 
      
  • Proxy

    • //生成代理类

    • //生成代理类
      public Object getProxy(){
          return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                                        rent.getClass().getInterfaces(),this);
      }
      
  1. 实现

    • 实体类

      //抽象角色:租房
      public interface Rent {
          public void rent();
      }
      
    • Host真实角色

      //真实角色: 房东,房东要出租房子
      public class Host implements Rent{
          public void rent() {
              System.out.println("房屋出租");
          }
      }
      
    • ProxyInvocationHandler. java 即代理角色

      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);
          }
      
          // proxy : 代理类 method : 代理类的调用处理程序的方法对象.
          // 处理代理实例上的方法调用并返回结果
          @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("收中介费");
          }
      
      }
      
    • Client . java

      public class Test {
          public static void main(String[] args) {
              //真实对象
              Host host = new Host();
              //代理对象的调用处理程序
              ProxyInvocationHandler pih = new ProxyInvocationHandler();
              pih.setRent(host); //设置要代理的对象
              UserService proxy = (UserService)pih.getProxy(); //动态生成代理类!
              proxy.delete();
          }
      }
      

四、动态代理的好处

静态代理有的它都有,静态代理没有的,它也有!

  • 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .
  • 公共的业务由代理来完成 . 实现了业务的分工 ,
  • 公共业务发生扩展时变得更加集中和方便 .
  • 一个动态代理 , 一般代理某一类业务
  • 一个动态代理可以代理多个类,代理的是接口!
posted @ 2020-03-03 16:03  梦想与爱  阅读(227)  评论(0编辑  收藏  举报