zoukankan      html  css  js  c++  java
  • 23种设计模式----------代理模式(三) 之 动态代理模式

    (上一篇)种设计模式----------代理模式(二)

    当然代理模式中,用的最广泛的,用的最多的是  动态代理模式。

    动态代理:就是实现阶段不用关系代理是哪个,而在运行阶段指定具体哪个代理。

    抽象接口的类图如下:

          --图来自设计模式之禅

    所以动态代理模式要有一个InvocationHandler接口 和 GamePlayerIH实现类。其中 InvocationHandler是JD提供的动态代理接口,对被代理类的方法进行代理。

    代码实现如下

    抽象主题类或者接口:

     1 package com.yemaozi.proxy.dynamic;
     2 
     3 /*
     4  * 动态代理:就是实现阶段不用关系代理是哪个,而在运行阶段指定具体哪个代理。
     5  */
     6 public interface IGamePlayer {
     7     //登录游戏
     8     public void login(String username, String password);
     9     
    10     //击杀Boss
    11     public void killBoss();
    12     
    13     //升级
    14     public void upGrade();
    15 }

    需要被代理类:

     1 package com.yemaozi.proxy.dynamic;
     2 
     3 public class GamePlayer implements IGamePlayer {
     4     
     5     private String name = "";
     6     
     7     public GamePlayer(String name){
     8         this.name = name;
     9     }
    10     
    11     public void login(String username, String password) {
    12         System.out.println("登录名为 "+username+" 进入游戏," + name + " 登录成功!");
    13     }
    14         
    15     public void killBoss() {
    16         System.out.println(this.name + " 击杀了Boss!");
    17     }
    18 
    19     public void upGrade() {
    20         System.out.println(this.name + "升级了!");
    21     }
    22 
    23 }

    动态代理处理器类:

     1 package com.yemaozi.proxy.dynamic;
     2 
     3 import java.lang.reflect.InvocationHandler;
     4 import java.lang.reflect.Method;
     5 
     6 public class GamePlayerInvocationHandler implements InvocationHandler{
     7 
     8     //被代理的对象
     9     private Object obj;
    10     
    11     //将需要代理的实例通过处理器类的构造方法传递给代理。
    12     public GamePlayerInvocationHandler(Object obj){
    13         this.obj = obj;
    14     }
    15     
    16     public Object invoke(Object proxy, Method method, Object[] args)
    17             throws Throwable {
    18         Object result = null;
    19         if("login".equalsIgnoreCase(method.getName())){
    20             //这个在主题方法不受任何影响的情况下,在主题方法前后添加新的功能,或者增强主题方法,
    21             //从侧面切入从而达到扩展的效果的编程,就是面向切面编程(AOP Aspect Oriented Programming)。
    22             //AOP并不是新技术,而是相对于面向对象编程的一种新的编程思想。在日志,事务,权限等方面使用较多。
    23             System.out.println("代理登录游戏!");
    24             result = method.invoke(this.obj, args);
    25             return result;
    26         }
    27         result = method.invoke(this.obj, args);
    28         return result;
    29     }
    30 
    31 }

    由于代理是动态产生的,所以不需要再声明代理类。

    动态代理场景类:

    package com.yemaozi.proxy.dynamic;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
    
    public class Client {
        public static void main(String[] args) {
            IGamePlayer gp = new GamePlayer("张三");
            InvocationHandler gpHandler = new GamePlayerInvocationHandler(gp);
            //获取真实主题类的ClassLoader
            ClassLoader classLoader = gp.getClass().getClassLoader();
            //动态产生一个代理者。
            Class<?>[] cls = new Class[]{IGamePlayer.class};
            IGamePlayer proxyGp = (IGamePlayer) Proxy.newProxyInstance(classLoader, cls, gpHandler);
            proxyGp.login("zhangsan", "123456");
            proxyGp.killBoss();
            proxyGp.upGrade();
        }
    }
    
    执行结果:
    代理登录游戏!
    登录名为 zhangsan 进入游戏,张三 登录成功!
    张三 击杀了Boss!
    张三升级了!
    
    //在此,我们没有创建代理类,但是确实有代理类帮我们完成事情。

    其中,在此代理模式中,不仅代理是动态产生的(即在运行的时候生成),而且还在代理的时候,也增加了一些处理。在此处增加的处理,其实就是另一种编程思想-----面向切面编程思想(AOP Aspect Oriented Programming)。

    带有AOP的动态代理模式类图:

            --图来自设计模式之禅

    从上图中,可以看出有两个相对独立的模块(Subject和InvocationHandler)。动态代理实现代理的职责,业务逻辑Subject实现相关的逻辑功能,两者之间没有必然的相互耦合的关系。然而,通知Advice从另一个切面切入,最终在上层模块就是Client耦合,完成逻辑的封装。

    代码清单如下

    抽象主题或者接口:

    1 package com.yemaozi.proxy.dynamic_aop;
    2 
    3 public interface Subject {
    4     public void doSomething(String str);
    5     //...可以多个逻辑处理方法。。。
    6 }

    真实主题:

     1 package com.yemaozi.proxy.dynamic_aop;
     2 
     3 public class RealSubject implements Subject{
     4 
     5     public void doSomething(String str) {
     6         //do something...
     7         System.out.println("do something..." + str);
     8     }
     9 
    10 }

    通知接口:

    1 package com.yemaozi.proxy.dynamic_aop;
    2 
    3 //通知接口及定义、
    4 public interface IAdvice {
    5     public void exec();
    6 }

    前置通知:

    1 package com.yemaozi.proxy.dynamic_aop;
    2 
    3 public class BeforeAdvice implements IAdvice {
    4     //在被代理的方法前来执行,从而达到扩展功能。
    5     public void exec() {
    6         System.out.println("前置通知被执行!");
    7     }
    8 }

    后置通知:

    1 package com.yemaozi.proxy.dynamic_aop;
    2 
    3 public class AfterAdvice implements IAdvice {
    4     
    5     //在被代理的方法后来执行,从而达到扩展功能。
    6     public void exec() {
    7         System.out.println("后置通知被执行!");
    8     }
    9 }

    动态代理的处理器类:

    所有的方法通过invoke方法类实现。

     1 package com.yemaozi.proxy.dynamic_aop;
     2 
     3 import java.lang.reflect.InvocationHandler;
     4 import java.lang.reflect.Method;
     5 
     6 public class MyInvocationHandler implements InvocationHandler {
     7 
     8     //被代理的对象
     9     private Subject realSubject;
    10     //通过MyInvocationHandler的构造方法将被代理对象传递过来。
    11     public MyInvocationHandler(Subject realSubject){
    12         this.realSubject = realSubject;
    13     }
    14     //执行被代理类的方法。
    15     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    16         //在执行方法前,执行前置通知。
    17         IAdvice beforeAdvice = new BeforeAdvice();
    18         beforeAdvice.exec();
    19         Object result = method.invoke(this.realSubject, args);
    20         //在执行方法后,执行后置通知。
    21         IAdvice afterAdvice = new AfterAdvice();
    22         afterAdvice.exec();
    23         //前置通知,和后置通知,都是要看具体实际的业务需求来进行添加。
    24         return result;
    25     }
    26 
    27 }

    动态代理类:

     1 package com.yemaozi.proxy.dynamic_aop;
     2 
     3 import java.lang.reflect.InvocationHandler;
     4 import java.lang.reflect.Proxy;
     5 
     6 public class DynamicProxy {
     7     
     8     /**
     9      * public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler handler)
    10      * loader:
    11      *             一个ClassLoader对象,定义了由哪个ClassLoader对象,来对生产的代理进行加载。
    12      * interfaces:
    13      *             一个Interfaces数组,表示我将要给我所代理的对象提供一组什么样的接口,
    14      *             如果提供一组接口给它,那么该代理对象就宣称实现了该接口,从而可以调用接口中的方法。
    15      *             即,查找出真是主题类的所实现的所有的接口。
    16      * handler:
    17      *             一个InvocationHandler对象,表示当我这个动态代理对象在调用方法时,会关联到该InvocationHandler对象。
    18      *             该InvocationHandler与主题类有着关联。
    19      */
    20     public static <T> T newProxyInstance(ClassLoader classLoader, Class<?>[] interfaces, InvocationHandler handler){
    21         @SuppressWarnings("unchecked")
    22         T t = (T) Proxy.newProxyInstance(classLoader, interfaces, handler);
    23         return t;
    24     }
    25 }

    从动态的产生动态代理类。

    动态代理场景类:

     1 package com.yemaozi.proxy.dynamic_aop;
     2 
     3 import java.lang.reflect.InvocationHandler;
     4 
     5 public class AOPClient {
     6     
     7     public static void main(String[] args) {
     8         Subject realSubject = new RealSubject();
     9         InvocationHandler handler = new MyInvocationHandler(realSubject); 
    10         ClassLoader classLoader = realSubject.getClass().getClassLoader();
    11         Class<?>[] interfaces = realSubject.getClass().getInterfaces();
    12         Subject proxySubect = DynamicProxy.newProxyInstance(classLoader, interfaces, handler);
    13         proxySubect.doSomething("这是一个Dynamic AOP示例!!!");
    14     }
    15 }
    16 
    17 执行结果:
    18 前置通知被执行!
    19 do something...这是一个Dynamic AOP示例!!!
    20 后置通知被执行!

    动态代理中invoke的动态调用:

    动态代理类DynamicProxy是个纯粹的动态创建代理类通用类。

    所以在具体业务中,可以在进一步封装具体的具有业务逻辑意义的DynamicProxy类。

    代码如下

    具体业务的动态代理:

     1 package com.yemaozi.proxy.dynamic_aop;
     2 
     3 import java.lang.reflect.InvocationHandler;
     4 //具体业务的动态代理。
     5 public class SubjectDynamicProxy extends DynamicProxy {
     6     public static <T> T newProxyInstance(Subject subject){
     7         ClassLoader classLoader = subject.getClass().getClassLoader();
     8         Class<?>[] interfaces = subject.getClass().getInterfaces();
     9         InvocationHandler handler = new MyInvocationHandler(subject);
    10         T t = newProxyInstance(classLoader, interfaces, handler);
    11         return t;
    12     }
    13 }

    动态代理在现在用的是非常的多的,如像Spring AOP ,DBCP连接池,AspectJ等。。。

  • 相关阅读:
    监听事件 队列 邮件发送
    elasticsearch 天气
    elasticsearch
    event 监听事件
    observer 监听的实现 laravel 框架
    中间件
    git 代码 上传到码云
    laravel 省略入口文件 index.php
    limit offset 和limit
    CSS变形和动画
  • 原文地址:https://www.cnblogs.com/yemaozistar/p/4162032.html
Copyright © 2011-2022 走看看