Spring的Aop的代理模式学习

70 阅读5分钟

代理模式

代理模式,就是SpringAop的底层。【SpringAop和SpringMVC】

代理模式的分类

  1. 动态代理
  2. 静态代理

1静态代理

角色分析:

  1. 抽象角色:一般会使用抽象类或者接口来解决
  2. 真实角色:被代理的角色
  3. 代理角色:代理真实角色,代理之后可以进行一些附属操作
  4. 客户:访问代理角色的人

优点

  1. 真实角色的操作更加纯粹,不用关注公共业务
  2. 公共业务交给代理角色,实现了业务的分工。(出租房是房东的事情,现在由中介代替)
  3. 公共业务发生扩展时候,方便集中管理。

缺点

  1. 一个真实角色就需要一个代理角色。真实角色多的时候,代码量会翻倍;

案例

  1. 接口
 // 租房
 public interface Rent{
   public void rent(); //租房方法
 }
  1. 真实角色
//房东,
public class  Host implements Rent{
   public void rent(){
     System.out.println("房东要出租房子!");
   }
}
  1. 代理角色
//代理角色 proxy
public class Proxy implements Rent{
   private Host host;//将房东组合进来,
   public Proxy(){}
   public Proxy(Host host){
     this.host=host
   }
   public void rent(){ //租房
    seeHouse();
     hrtong();
     host.rent();
   }
   // 附属操作
   public void seeHouse(){
      System.out.println("中介带你看房!")
   }
   public void hetong(){
     System.out.println("签租赁合同")
   }
}
  1. 客户端访问代理角色
//客户端
public class Client {
  public static void main(String[] args){
    // 房东
    Host host = new Host();
    // 中介,中介代理房东
    Proxy proxy = new Proxy(host);
    //中介出租房
    proxy.rent();
  }
}

加深理解,在执行方法的时候添加日志

方法接口

public interface service{
   public void add();
   public void delete();
   public void update();
   public void query();
}

实现类

public class serviceImpl implements Service{
    public void add(){
      System.out.println("新增一个客户!")
    }
     public void delete(){
      System.out.println("删除一个客户!")
    }
     public void update(){
      System.out.println("更新一个客户!")
    }
     public void query(){
      System.out.println("查询一个客户!")
    }
}

客户端类

public class Client{
  public static void main(String[] args){
     ServiceImpl servieImpl = new ServiceImpl();
     servieImpl.add();
  }
}

新需求:给每个方法新增一个打印日志的方法

新增一个代理类

public class Proxy implements Service{
  private ServiceImpl serviceImpl;
  public void setServiceImpl(ServiceImpl serviceImpl){
    return this.serviceImpl=serviceImpl;
  }
     public void add(){
       log(add);
      System.out.println("新增一个客户!")
    }
     public void delete(){
      log(delete);
      System.out.println("删除一个客户!")
    }
     public void update(){
      log(update);
      System.out.println("更新一个客户!")
    }
     public void query(){
      log(query);
      System.out.println("查询一个客户!")
    }
    //新增 日志方法
    public void log(String msg){
      System.out.println("执行了"+msg+"方法");
    }


}

客户端类

public class Client{
   public static void main(String[] args){
      ServiceImpl serviceImpl = new ServiceImpl();
      Proxy proxy = new Proxy();
      proxy.setServiceImpl(serviceImpl);
      proxy.add();  
   }
}

 

2 动态代理

动态代理的底层是反射。

动态代理和静态代理的角色一样。动态代理的类是动态生成的

动态代理分类:

  1. 基于接口的动态代理:JDK代理【案例使用这种方法】
  2. 基于类的动态代理:cglib,现在用的比较多的是 Java字节码:javassist

优点

  1. 真实角色的操作更加纯粹,不用关注公共业务
  2. 公共业务交给代理角色,实现了业务的分工。(出租房是房东的事情,现在由中介代替)
  3. 公共业务发生扩展时候,方便集中管理。
  4. 一个动态代理代理的是一个接口,一般是这一类业务
  5. 一个动态代理可以代理多个类,只要实现的是同一个接口即可。(只要实现了租房接口,其他的不用改,只需要将客户端类中的真实角色修改即可。)

 

案例

  1. 接口
//租房
public class Rent{
  public void rent();
}
  1. 真实角色
//房东,
public class  Host implements Rent{
   public void rent(){
     System.out.println("房东要出租房子!");
   }
}
  1. 代理角色
//代理
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().getInterface(),this);
  }  
  
  // 处理代理实例,并返回结果。  调用代理的执行方法
  public Object invoke(Object proxy,Method method,Object[] args) throws  Throwable {
  //动态代理的本质就是使用反射机制
   seeHouse();
    Object result = method.invoke(rent,args);
    return result;
  }
  
  public void seeHouse(){
    System.out.println("中介带你看房");
  }


}
  1. 客户端
public class Client{
  public static void main(String[] args){
    // 真实角色
    Host host = new host();
    //代理角色,这里不存在
    ProxyInvocationHandler pih = new ProxyInvocationHandler();
    //通过调用程序处理角色来处理我们要调用的接口对象
    pih.setRent(host);
    // proxy就是动态生成的代理
    Rent proxy = (Rent) pih.getProxy();
    proxy.rent();
  }
}

加深理解,在执行方法的时候添加日志

方法接口

public interface service{
   public void add();
   public void delete();
   public void update();
   public void query();
}

实现类

public class serviceImpl implements Service{
    public void add(){
      System.out.println("新增一个客户!")
    }
     public void delete(){
      System.out.println("删除一个客户!")
    }
     public void update(){
      System.out.println("更新一个客户!")
    }
     public void query(){
      System.out.println("查询一个客户!")
    }
}

动态代理类

public class ProxyInvocationHandler implements InvocationHandler {
   //被代理的接口
   private Object target; // Object类,接收类型,这个方法这个定义为一个工具类的写法/模板类的写法
   public void setTarget(Object target){
     return this.target=target;
   }
    
// 生成得到的代理类
  public Object getProxy(){
    return Proxy.newProxyInstance(this.getClass().getClassLoader,target.getClass().getInterface(),this);
      }   
      //处理代理实例,并返回结果
    public Object invoke(Object proxy,Method method,Object[] args){
     Object result = method.invoke(target,args);
     return result;  
    }


}

客户端

public class Client{
   public static void main(Stirng[] args){
    //真实角色
     ServiceImpl serviceImpl = new ServiceImpl();
     //代理角色。只是被创建,还没初始化。
     ProxyInvocationHandler  pih = new ProxyInvocationHandler();
     //设置代理对象
     pih.setTarget(serviceImpl);
     //创建代理对象,动态生成代理类
     ServiceImpl proxy = (ServiceImpl)pih.getProxy();
     proxy.add();
   }
}

新需求:给每个方法新增一个打印日志的方法

这里是动态代理,不需要新建一个代理类,修改原 动态代理类

public class ProxyInvocationHandler implements InvocationHandler {
   //被代理的接口
   private Object target; // Object类,接收类型,这个方法这个定义为一个工具类的写法/模板类的写法
   public void setTarget(Object target){
     return this.target=target;
   }
    
// 生成得到的代理类
  public Object getProxy(){
    return Proxy.newProxyInstance(this.getClass().getClassLoader,target.getClass().getInterface(),this);
      }   
      //处理代理实例,并返回结果
    public Object invoke(Object proxy,Method method,Object[] args){
     log(method.getName());
     Object result = method.invoke(target,args);
     return result;  
    }
    
    public void log(String args){
       System.out.println("执行了"+args+"方法")
    }


}