【Spring】(十)代理模式

代理模式

  • 为什么要学习代理模式?

    因为这是Spring AOP的底层。【SpringAOP 和 SpringMVC】

  • 代理模式的分类:

    • 静态代理
    • 动态代理

1.静态代理

  • 例子:

  • 角色分析:

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

代码

  • 1.Rent 接口

    //租房
    public interface Rent {
        public void rent();
    }
    
  • 2.Host 真实角色

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

    //租房中介
    public class Proxy implements Rent {
    
        private Host host;
    
        public Proxy() {
        }
    
        public Proxy(Host host) {
            this.host = host;
        }
    
        public void rent() {
            this.seeHouse();
            host.rent();
            this.hetong();
            this.fare();
        }
    
        //看房
        public void seeHouse() {
            System.out.println("中介带你看房");
        }
    
        //合同
        public void hetong() {
            System.out.println("签租赁合同");
        }
    
        //收中介费
        public void fare() {
            System.out.println("收中介费");
        }
    }
    
  • 4.Client 客户端访问代理角色

    //客户
    public class Client {
    
        public static void main(String[] args) {
            //房东要租房子
            Host host = new Host();
            //代理,中介帮房东租房子,但是代理角色一般会有一些附属操作
            Proxy proxy = new Proxy(host);
    
            //不用面对房东,直接找中介租房即可
            proxy.rent();
        }
    }
    


  • 代理模式的好处:
    • 可以使真实角色的操作更加纯粹。不用去关注一些公共的业务。
    • 公共业务交给代理角色。实现了业务的分工。
    • 公共业务发生扩展的时候,方便集中管理。
  • 缺点:
    • 一个真实角色会产生一个代理角色;代码量会翻倍,开发效率变低

2 加深理解(关于公共业务扩展的说明)

​ 例子2

  • 测试环境

    1.UserService

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

    //真实对象
    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("查询了一个用户");
        }
    
    }
    
  • 3.Cilent

    public class Cilent {
        public static void main(String[] args) {
            UserServiceImpl userService=new UserServiceImpl();
            userService.add();
        }
    }
    

​ 若想在原本业务的基础上,在UserServiceImpl中每个方法前输出自己写的日志语句,就要在原代码上进行修改,在工程量的情况下很麻烦且修改后可能会出现bug。

​ 公共业务扩展,可以使用代理模式。

  • 增加类 UserServiceProxy

    //代理角色
    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("[Debug] 使用了" + msg + "方法");
        }
    }
    
  • 修改类 Client

    public class Cilent {
        public static void main(String[] args) {
            UserServiceImpl userService=new UserServiceImpl();
    
            UserServiceProxy proxy=new UserServiceProxy();
            proxy.setUserService(userService);
    
            proxy.add();
        }
    }
    


  • AOP的实现机制


3.动态代理

  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成的,不是直接写好的
  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
    • 基于接口 --- JDK 动态代理【下面例子使用的】
    • 基于类:cglib
    • java字节码实现:javasist

  • 需要了解两个类:Proxy 代理;InvocationHandler 调用处理程序

  • 1.公共工具类 ProxyInvocationHandler

    //用这个类,自动生成代理类
    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);
        }
    
        //处理代理实例,并返回结果
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            log(method.getName());
            Object result = method.invoke(target, args);
            return result;
        }
    
        public void log(String msg) {
            System.out.println("执行了" + msg + "方法");
        }
    }
    
  • 2.UserService

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

    //真实对象
    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("查询了一个用户");
        }
    }
    
  • 4.Client

    public class Client {
        public static void main(String[] args) {
            //真实角色
            UserServiceImpl userService=new UserServiceImpl();
            //代理角色,不存在
            ProxyInvocationHandler pih=new ProxyInvocationHandler();
    
            pih.setTarget(userService);//设置要代理的对象
            //动态生成代理类
            UserService proxy = (UserService) pih.getProxy();
    
            proxy.query();
        }
    }
    



  • 动态代理的好处:

    • 可以使真实角色的操作更加纯粹。不用去关注一些公共的业务。

    • 公共业务交给代理角色。实现了业务的分工。

    • 公共业务发生扩展的时候,方便集中管理。

    • 一个动态代理类代理的是一个接口,一般就是对应的一类业务

      如果要变成代理某个具体接口的动态代理类,只需要改动该接口相关的代码即可。

      public class ProxyInvocationHandler implements InvocationHandler {
      
          //被代理的接口
          private Object target;
          。。。
      }
      
    • 一个动态代理类可以代理多个类,只要是实现了同一个接口即可。

      继承了接口UserService的实现类,只要修改对象userService就能直接用了。

      public class Client {
          public static void main(String[] args) {
              //真实角色
              UserServiceImpl userService=new UserServiceImpl();
              //代理角色,不存在
              ProxyInvocationHandler pih=new ProxyInvocationHandler();
      
              pih.setTarget(userService);//设置要代理的对象
              //动态生成代理类
              UserService proxy = (UserService) pih.getProxy();
      
              proxy.query();
          }
      }
      
posted @ 2021-01-26 22:10  musecho  阅读(117)  评论(0)    收藏  举报