zoukankan      html  css  js  c++  java
  • 7.代理模式

    本文转载:https://blog.kuangstudy.com/index.php/archives/526/

    一.代理模式

    1.什么是代理模式

    为什么要学习代理模式,因为AOP的底层机制就是动态代理!

    代理模式:

    • 静态代理

    • 动态代理

    学习aop之前 , 我们要先了解一下代理模式!

    1570016650994.png

    租房案例:

    2.静态代理

    静态代理角色分析

    • 抽象角色 : 一般使用接口或者抽象类来实现

    • 真实角色 : 被代理的角色

    • 代理角色 : 代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作 .

    • 客户 : 使用代理角色来进行一些操作 .

    (1)抽象角色:租房Rent.java

    1 //抽象角色:租房
    2 public interface Rent {
    3 
    4     void rent();
    5 }

    (2)真实角色:房东Host.java

    1 //真实角色: 房东,房东要出租房子
    2 public class Host implements Rent{
    3     public void rent() {
    4         System.out.println("房屋出租");
    5     }
    6 }

    (3)代理角色:Proxy.java

     1 //代理角色:中介
     2 public class Proxy implements Rent {
     3 
     4     private Host host;
     5     public Proxy() { }
     6     public Proxy(Host host) {
     7         this.host = host;
     8     }
     9 
    10     //租房
    11     public void rent(){
    12         seeHouse();
    13         host.rent();
    14         fare();
    15     }
    16     //看房
    17     public void seeHouse(){
    18         System.out.println("带房客看房");
    19     }
    20     //收中介费
    21     public void fare(){
    22         System.out.println("收中介费");
    23     }
    24 }

    (4)租客角色:Client.java

     1 //客户类,一般客户都会去找代理!
     2 public class Client {
     3     public static void main(String[] args) {
     4         //房东要租房
     5         Host host = new Host();
     6         //中介帮助房东
     7         Proxy proxy = new Proxy(host);
     8 
     9         //你去找中介!
    10         proxy.rent();
    11     }
    12 }

    3.静态代理优缺点分析

    • 优点:

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

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

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

    • 缺点:

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

    4.静态代理深入理解

    (1)业务层抽象接口:UserService.java

    1 //抽象角色:增删改查业务
    2 public interface UserService {
    3     void add();
    4     void delete();
    5     void update();
    6     void query();
    7 }

    (2)业务层实现类:UserServiceImpl

     1 //真实对象,完成增删改查操作的人
     2 public class UserServiceImpl implements UserService {
     3 
     4     public void add() {
     5         System.out.println("增加了一个用户");
     6     }
     7 
     8     public void delete() {
     9         System.out.println("删除了一个用户");
    10     }
    11 
    12     public void update() {
    13         System.out.println("更新了一个用户");
    14     }
    15 
    16     public void query() {
    17         System.out.println("查询了一个用户");
    18     }
    19 }

    (3)代理角色:用来添加日志功能UserServiceProxy.java

     1 //代理角色,在这里面增加日志的实现
     2 public class UserServiceProxy implements UserService {
     3     private UserServiceImpl userService;
     4 
     5     public void setUserService(UserServiceImpl userService) {
     6         this.userService = userService;
     7     }
     8 
     9     public void add() {
    10         log("add");
    11         userService.add();
    12     }
    13 
    14     public void delete() {
    15         log("delete");
    16         userService.delete();
    17     }
    18 
    19     public void update() {
    20         log("update");
    21         userService.update();
    22     }
    23 
    24     public void query() {
    25         log("query");
    26         userService.query();
    27     }
    28 
    29     public void log(String msg){
    30         System.out.println("执行了"+msg+"方法");
    31     }
    32 
    33 }

    (4)用户类:Client.java

     1 public class Client {
     2     public static void main(String[] args) {
     3         //真实业务
     4         UserServiceImpl userService = new UserServiceImpl();
     5         //代理类
     6         UserServiceProxy proxy = new UserServiceProxy();
     7         //使用代理类实现日志功能!
     8         proxy.setUserService(userService);
     9 
    10         proxy.add();
    11     }
    12 }

    (5)总结

    • 我们在不改变原来的代码的情况下,实现了对原有功能的增强,这是AOP中最核心的思想

    5.动态代理

    • 动态代理和静态代理角色一样

    • 动态代理的代理类是动态生成的,不是我们直接写好的

    • 动态代理大致上分为两大类:(基于接口和基于类的)

      • 基于接口:经典的是JDK的动态代理

      • 基于类:例如:cglib

      • java字节码实现:现在用的比较多的是 javasist 来生成动态代理 . 百度一下javasist

      • 我们这里使用JDK的原生代码来实现,其余的道理都是一样的!

    (1)动态代理实现

    JDK的动态代理需要了解两个类

    • 核心 : InvocationHandler 和 Proxy 

    • InvocationHandler:调用处理程序类

    • Proxy:创建动态代理类

    抽象租房角色:Rent.java

    1 //抽象角色:租房
    2 public interface Rent {
    3 
    4     void rent();
    5 }

    真实租房角色:Host.java

    1 //真实角色: 房东,房东要出租房子
    2 public class Host implements Rent {
    3     public void rent() {
    4         System.out.println("房屋出租");
    5     }
    6 }

    代理角色:ProxyInvocationHandler. java

     1 import java.lang.reflect.InvocationHandler;
     2 import java.lang.reflect.Method;
     3 import java.lang.reflect.Proxy;
     4 
     5 public class ProxyInvocationHandler implements InvocationHandler {
     6     private Rent rent;
     7 
     8     public void setRent(Rent rent) {
     9         this.rent = rent;
    10     }
    11 
    12     //生成代理类,重点是第二个参数,获取要代理的抽象角色!之前都是一个角色,现在可以代理一类角色
    13     public Object getProxy(){
    14         return Proxy.newProxyInstance(this.getClass().getClassLoader(),
    15                 rent.getClass().getInterfaces(),this);
    16     }
    17 
    18     // proxy : 代理类 method : 代理类的调用处理程序的方法对象.
    19     // 处理代理实例上的方法调用并返回结果
    20     @Override
    21     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    22         seeHouse();
    23         //核心:本质利用反射实现!
    24         Object result = method.invoke(rent, args);
    25         fare();
    26         return result;
    27     }
    28 
    29     //看房
    30     public void seeHouse(){
    31         System.out.println("带房客看房");
    32     }
    33     //收中介费
    34     public void fare(){
    35         System.out.println("收中介费");
    36     }
    37 
    38 }

    租客角色:Client . java

     1 //客户类
     2 public class Client {
     3     public static void main(String[] args) {
     4         //真实角色
     5         Host host = new Host();
     6         //代理实例的调用处理程序
     7         ProxyInvocationHandler pih = new ProxyInvocationHandler();
     8         pih.setRent(host); //将真实角色放置进去!
     9         Rent proxy = (Rent) pih.getProxy(); //动态生成对应的代理类!
    10         proxy.rent();
    11     }
    12 }

    (2)动态代理深入理解

    • 我们来使用动态代理实现代理我们后面写的UserService!

    • 我们也可以编写一个通用的动态代理实现的类!所有的代理对象设置为Object即可!

    代理角色:ProxyInvocationHandler. java

     1 public class ProxyInvocationHandler implements InvocationHandler {
     2     private Object target;
     3 
     4     public void setTarget(Object target) {
     5         this.target = target;
     6     }
     7 
     8     //生成代理类
     9     public Object getProxy(){
    10         return Proxy.newProxyInstance(target.getClass().getClassLoader(),
    11                 target.getClass().getInterfaces(),this);
    12     }
    13 
    14     // proxy : 代理类
    15     // method : 代理类的调用处理程序的方法对象.
    16     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    17         log(method.getName());
    18         Object result = method.invoke(target, args);
    19         return result;
    20     }
    21 
    22     public void log(String methodName){
    23         System.out.println("执行了"+methodName+"方法");
    24     }
    25 
    26 }

    客户角色:Client.java

     1 public class Client {
     2     public static void main(String[] args) {
     3         //真实对象
     4         UserServiceImpl userService = new UserServiceImpl();
     5         //代理对象的调用处理程序
     6         ProxyInvocationHandler pih = new ProxyInvocationHandler();
     7         pih.setTarget(userService); //设置要代理的对象
     8         UserService proxy = (UserService)pih.getProxy(); //动态生成代理类!
     9         proxy.delete();
    10     }
    11 }

    (3)动态代理的好处

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

    • 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .

    • 公共的业务由代理来完成 . 实现了业务的分工 ,

    • 公共业务发生扩展时变得更加集中和方便 .

    • 一个动态代理 , 一般代理某一类业务

    • 一个动态代理可以代理多个类,代理的是接口!

     6.总结:

    (1)静态代理特点:代理类(UserServiceProxy)和被代理类(UserServiceImpl)在编译期间就确定下来了

    (2)动态代理特点:

    1. 代理类是在代码运行时才能确定下来的,通过ProxyInvocationHandler创建出代理类

    2. 可以灵活的通过不同的被代理类创建不同的代理类

  • 相关阅读:
    GPU 版 TensorFlow failed to create cublas handle: CUBLAS_STATUS_ALLOC_FAILED
    Python -- 值转换为字符串的两种机制
    Python
    vim中注释多行python代码
    HTTP协议状态码详解(HTTP Status Code)
    关于Python报错:SyntaxError: Non-ASCII character 'xe5' in file的解决方法
    Linux如何查看进程、杀死进程、启动进程等常用命令
    vim 如何设置显示行号和缩进
    一、报错
    二、极光推送
  • 原文地址:https://www.cnblogs.com/zhihaospace/p/12326075.html
Copyright © 2011-2022 走看看