zoukankan      html  css  js  c++  java
  • 第三节:代理模式——动态代理

    一、动态代理模式的基本介绍

      1、代理对象,不需要实现接口,但是目标对象要实现接口,否则不能动态代理;

      2、代理对象的生成,是利用 JDK 的 API,动态的在内存中构建代理对象;

      3、动态代理也叫做:JDK 代理、接口代理

      4、实现步骤

        (1)代理对象和真实对象实现相同的接口;

        (2)代理对象 = Proxy.newProxyInstance();

        (3)使用代理对象调用方法

        (4)增强方法

          增强方法方式:

            ① 增强参数列表

            ② 增强返回值类型

            ③ 增强方法体执行逻辑

    二、JDK 中生成代理对象的 API

      1、代理类所在包:java.lang.reflect.Proxy

      2、JDK 实现代理只需要使用 newProxyInstance 方法,但是该方法需要接受三个参数,完整的写法是:

    1  public static Object newProxyInstance(ClassLoader loader,
    2                                           Class<?>[] interfaces,
    3                                           InvocationHandler h)

    三、动态代理应用实例

      将上一节的静态代理改进成动态代理模(即:JDK代理模式

      1、UML 类图

        

      2、代码实现:

        接口:

    1 /**
    2  * 接口
    3  */
    4 public interface ITeacherDao {
    5     void teach(); //授课
    6 
    7     void sayHello(String name);
    8 }

        被代理对象(目标对象):

     1 public class TeacherDao implements ITeacherDao{
     2     @Override
     3     public void sayHello(String name) {
     4         System.out.println("Hello," + name);
     5     }
     6 
     7     @Override
     8     public void teach() {
     9         System.out.println("老师授课中。。。");
    10     }
    11 }

        代理工厂:

     1 public class ProxyFactory {
     2 
     3     //维护一个目标对象,Object
     4     private Object target;
     5 
     6     /**
     7      * 通过构造方法,对 target 进行初始化
     8      */
     9     public ProxyFactory(Object target) {
    10         this.target = target;
    11     }
    12 
    13     /**
    14      *  给目标对象 生成一个代理对象
    15      * @return
    16      */
    17     public Object getProxyInstance() {
    18         /**
    19          * public static Object newProxyInstance(ClassLoader loader,
    20          *                                     Class<?>[] interfaces,
    21          *                                     InvocationHandler h)
    22          * 参数说明:
    23          *  1、ClassLoader loader:
    24          *      指定当前目标对象使用的类加载器,获取加载器的方法固定的
    25          *  2、Class<?>[] interfaces
    26          *      目标对象(被代理对象)实现的接口类型,使用泛型方式确认类型
    27          *  3、InvocationHandler h:
    28          *      事件处理,执行目标对象的方法时,会触发事件处理器方法,
    29          *      会把当前执行的目标对象方法作为一个参数传入
    30          */
    31         return Proxy.newProxyInstance(target.getClass().getClassLoader(),
    32                 target.getClass().getInterfaces(),
    33                 new InvocationHandler() {
    34 
    35                     @Override
    36                     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    37                         System.out.println("JDK代理开始");
    38                         //通过反射机制调用目标对象的方法
    39                         Object invoke = method.invoke(target, args);
    40                         System.out.println("JDK代理提交");
    41                         return invoke;
    42                     }
    43                 });
    44     }
    45 }

        客户端:

     1 public class Client {
     2     public static void main(String[] args) {
     3         //创建一个目标对象
     4         ITeacherDao target = new TeacherDao();
     5 
     6         //给目标对象创建代理对象,可以转成 ITeacherDAO
     7         ProxyFactory proxyFactory = new ProxyFactory(target);
     8         ITeacherDao proxyInstance = (ITeacherDao)proxyFactory.getProxyInstance();
     9 
    10         System.out.println("proxyInstance=" + proxyInstance);
    11         //proxyInstance类型=class com.sun.proxy.$Proxy0 内存中动态生成了代理对象
    12         System.out.println("proxyInstance类型=" + proxyInstance.getClass());
    13 
    14         //通过代理对象,调用目标对象的方法
    15         proxyInstance.teach();
    16 
    17         proxyInstance.sayHello("Tom");
    18     }
    19 }

    四、动态代理应用实例

      我们用买电脑这件事情来叙述一下动态代理:

      当我们想买一个联想电脑,而此时联想电脑公司在北京,我们在西安,如果买电脑还得去北京,比较浪费时间。

      这是在西安有一个联想代理商,我们可以从代理商这里预订一台电脑,而代理商去北京给我们取货。这样就形成了一种动态代理。

      

      在这里:

        北京联想公司=真实对象

        西安联想代理商=代理对象

      这里西安代理商可以把联想电脑销售到西安各地,扩大了销售市场,相当于增强了功能。

      代码演示

      卖电脑的接口类:

    1 public interface SaleComputer {
    2 
    3     public String sale(double money);
    4 
    5     public void show();
    6 }

      卖电脑真实类:

     1 /**
     2  * 真实类
     3  */
     4 public class Lenovo implements SaleComputer {
     5     @Override
     6     public String sale(double money) {
     7 
     8         System.out.println("花了"+money+"元买了一台联想电脑...");
     9         return "联想电脑";
    10     }
    11 
    12     @Override
    13     public void show() {
    14         System.out.println("展示电脑....");
    15     }
    16 }

      代理对象类

     1 import java.lang.reflect.InvocationHandler;
     2 import java.lang.reflect.Method;
     3 import java.lang.reflect.Proxy;
     4 
     5 public class ProxyTest {
     6 
     7     public static void main(String[] args) {
     8         //1.创建真实对象
     9         Lenovo lenovo = new Lenovo();
    10         
    11         //2.动态代理增强lenovo对象
    12         /*
    13             三个参数:
    14                 1. 类加载器:真实对象.getClass().getClassLoader()
    15                 2. 接口数组:真实对象.getClass().getInterfaces()
    16                 3. 处理器:new InvocationHandler()
    17          */
    18         SaleComputer proxy_lenovo = (SaleComputer) Proxy.newProxyInstance(lenovo.getClass().getClassLoader(), lenovo.getClass().getInterfaces(), new InvocationHandler() {
    19 
    20             /*
    21                 代理逻辑编写的方法:代理对象调用的所有方法都会触发该方法执行
    22                     参数:
    23                         1. proxy:代理对象
    24                         2. method:代理对象调用的方法,被封装为的对象
    25                         3. args:代理对象调用的方法时,传递的实际参数
    26              */
    27             @Override
    28             public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    29                 /*System.out.println("该方法执行了....");
    30                 System.out.println(method.getName());
    31                 System.out.println(args[0]);
    32 
    33 
    34 
    35 
    36 */
    37                 //判断是否是sale方法
    38                 if(method.getName().equals("sale")){
    39                     //1.增强参数
    40                     double money = (double) args[0];
    41                     money = money * 0.85;
    42                     System.out.println("专车接你....");
    43                     //使用真实对象调用该方法
    44                     String obj = (String) method.invoke(lenovo, money);
    45                     System.out.println("免费送货...");
    46                     //2.增强返回值
    47                     return obj+"_鼠标垫";
    48                 }else{
    49                     Object obj = method.invoke(lenovo, args);
    50                     return obj;
    51                 }
    52 
    53 
    54 
    55             }
    56         });
    57 
    58         //3.调用方法
    59 
    60         String computer = proxy_lenovo.sale(8000);
    61         System.out.println(computer);
    62 
    63         proxy_lenovo.show();
    64     }
    65 }
  • 相关阅读:
    笔记44 Hibernate快速入门(一)
    tomcat 启用https协议
    笔记43 Spring Security简介
    笔记43 Spring Web Flow——订购披萨应用详解
    笔记42 Spring Web Flow——Demo(2)
    笔记41 Spring Web Flow——Demo
    Perfect Squares
    Factorial Trailing Zeroes
    Excel Sheet Column Title
    Excel Sheet Column Number
  • 原文地址:https://www.cnblogs.com/niujifei/p/14364348.html
Copyright © 2011-2022 走看看