JAVA设计模式——代理(动态代理)

  传送门:JAVA设计模式——代理(静态代理)

  序言:

  在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足的我们的功能,我们更需要学习的是其底层是怎么样的一个原理,而AOP的原理就是java的动态代理机制,所以本篇随笔就是对java的动态机制进行一个回顾。

动态代理模式主要由四个元素共同构成:

  1. 接口,接口中的方法是要真正去实现的

  2. 被代理类,实现上述接口,这是真正去执行接口中方法的类

  3. InvocationHandler接口的实现,帮助被代理类去实现方法

  4. 代理类(Proxy)

一、InvocationHandler

在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。

每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。

我们来看看InvocationHandler这个接口的唯一一个方法 invoke方法:

Object invoke(Object proxy, Method method, Object[] args) throws Throwable

我们看到这个方法一共接受三个参数,那么这三个参数分别代表什么呢?

  • proxy: 指代我们所代理的那个真实对象
  • method:  指代的是我们所要调用真实对象的某个方法的Method对象
  • args:  指代的是调用真实对象某个方法时接受的参数

如果不是很明白,等下通过一个实例会对这几个参数进行更深的讲解。

二、Proxy类:

Proxy这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h)  throws IllegalArgumentException

这个方法的作用就是得到一个动态的代理对象,其接收三个参数,我们来看看这三个参数所代表的含义:

  • loader:  一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
  • interfaces:  一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
  • h:  一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

三、例子:

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

抽象接口的类图如下:

      --图来自设计模式之禅

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

代码实现如下

抽象主题类或者接口:

package com.yemaozi.proxy.dynamic;

/*
 * 动态代理:就是实现阶段不用关系代理是哪个,而在运行阶段指定具体哪个代理。
 */
public interface IGamePlayer {
    //登录游戏
    public void login(String username, String password);

    //击杀Boss
    public void killBoss();

    //升级
    public void upGrade();
}

被代理类:

package com.yemaozi.proxy.dynamic;

public class GamePlayer implements IGamePlayer {

    private String name = "";

    public GamePlayer(String name){
        this.name = name;
    }

    public void login(String username, String password) {
        System.out.println("登录名为 "+username+" 进入游戏," + name + " 登录        成功!");
    }

    public void killBoss() {
        System.out.println(this.name + " 击杀了Boss!");
    }

    public void upGrade() {
        System.out.println(this.name + "升级了!");
    }

}    

动态代理处理器类:

package com.yemaozi.proxy.dynamic;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class GamePlayerIHr implements InvocationHandler{

    //被代理的对象
    private Object obj;

    //将需要代理的实例通过处理器类的构造方法传递给代理。
    public GamePlayerIHr (Object obj){
        this.obj = obj;
    }

    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        Object result = null;
        if("login".equalsIgnoreCase(method.getName())){
            //这个方法不受任何影响的情况下,在方法前后添加新的功能,或者增强方法,
            //从侧面切入从而达到扩展的效果的编程,就是面向切面编程(AOP Aspect Oriented Programming)。
            //AOP并不是新技术,而是相对于面向对象编程的一种新的编程思想。在日志,事务,权限等方面使用较多。
            System.out.println("代理登录游戏!");
            result = method.invoke(this.obj, args);
            return result;
        }
        result = method.invoke(this.obj, args);
        return result;
    }

}

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

动态代理场景类:

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 GamePlayerIH(gp);
        //获取主题类的类加载器ClassLoader
        ClassLoader classLoader = gp.getClass().getClassLoader();
        //一个Interface对象的数组
        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

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

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

        --图来自设计模式之禅

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

代码清单如下

抽象主题或者接口:

package com.yemaozi.proxy.dynamic_aop;

public interface Subject {
    public void doSomething(String str);
    //...可以多个逻辑处理方法。。。
}

主题的实现类:

package com.yemaozi.proxy.dynamic_aop;

public class RealSubject implements Subject{

    public void doSomething(String str) {
        //do something...
        System.out.println("do something..." + str);
    }

}

AOP的通知接口:

package com.yemaozi.proxy.dynamic_aop;

//通知接口及定义、
public interface IAdvice {
    public void exec();
}

前置通知

package com.yemaozi.proxy.dynamic_aop;

public class BeforeAdvice implements IAdvice {
    //在被代理的方法前来执行,从而达到扩展功能。
    public void exec() {
        System.out.println("前置通知被执行!");
    }
}

后置通知:

package com.yemaozi.proxy.dynamic_aop;

public class AfterAdvice implements IAdvice {

    //在被代理的方法后来执行,从而达到扩展功能。
    public void exec() {
        System.out.println("后置通知被执行!");
    }
}

动态代理的处理器类:

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

package com.yemaozi.proxy.dynamic_aop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MyInvocationHandler implements InvocationHandler {

    //被代理的对象
    private Subject realSubject;
    //通过MyInvocationHandler的构造方法将被代理对象传递过来。
    public MyInvocationHandler(Subject realSubject){
        this.realSubject = realSubject;
    }
    //执行被代理类的方法。
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //在执行方法前,执行前置通知。
        IAdvice beforeAdvice = new BeforeAdvice();
        beforeAdvice.exec();
        Object result = method.invoke(this.realSubject, args);
        //在执行方法后,执行后置通知。
        IAdvice afterAdvice = new AfterAdvice();
        afterAdvice.exec();
        //前置通知,和后置通知,都是要看具体实际的业务需求来进行添加。
        return result;
    }

}

动态代理类(Proxy)

package com.yemaozi.proxy.dynamic_aop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class DynamicProxy {

    /**
     * public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler handler)
     * loader:
     *             一个ClassLoader对象,定义了由哪个ClassLoader对象,来对生产的代理进行加载。
     * interfaces:
     *             一个Interfaces数组,表示我将要给我所代理的对象提供一组什么样的接口,
     *             如果提供一组接口给它,那么该代理对象就宣称实现了该接口,从而可以调用接口中的方法。
     *             即,查找出真是主题类的所实现的所有的接口。
     * handler:
     *             一个InvocationHandler对象,表示当我这个动态代理对象在调用方法时,会关联到该InvocationHandler对象。
     *             该InvocationHandler与主题类有着关联。
     */
    public static <T> T newProxyInstance(ClassLoader classLoader, Class<?>[] interfaces, InvocationHandler handler){
        @SuppressWarnings("unchecked")
        T t = (T) Proxy.newProxyInstance(classLoader, interfaces, handler);
        return t;
    }
}

动态代理场景类:

package com.yemaozi.proxy.dynamic_aop;

import java.lang.reflect.InvocationHandler;

public class AOPClient {

    public static void main(String[] args) {
        Subject realSubject = new RealSubject();
        InvocationHandler handler = new MyInvocationHandler(realSubject);
        ClassLoader classLoader = realSubject.getClass().getClassLoader();
        Class<?>[] interfaces = realSubject.getClass().getInterfaces();
        Subject proxySubect = DynamicProxy.newProxyInstance(classLoader, interfaces, handler);
        proxySubect.doSomething("这是一个Dynamic AOP示例!!!");
    }
}

执行结果:
前置通知被执行!
do something...这是一个Dynamic AOP示例!!!
后置通知被执行!

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

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

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

代码如下

具体业务的动态代理:

package com.yemaozi.proxy.dynamic_aop;

import java.lang.reflect.InvocationHandler;
//具体业务的动态代理。
public class SubjectDynamicProxy extends DynamicProxy {
    public static <T> T newProxyInstance(Subject subject){
        ClassLoader classLoader = subject.getClass().getClassLoader();
        Class<?>[] interfaces = subject.getClass().getInterfaces();
        InvocationHandler handler = new MyInvocationHandler(subject);
        T t = newProxyInstance(classLoader, interfaces, handler);
        return t;
    }
}

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

原文地址:https://www.cnblogs.com/TvvT-kevin/p/9867851.html

时间: 2024-10-11 16:15:12

JAVA设计模式——代理(动态代理)的相关文章

深入解析Java设计模式之动态代理

深入解析Java设计模式之动态代理 代理是基本的设计模式之一,它是你为了提供额外的或不同的操作,而插入的用来代替"实际"对象的对象.这些操作通常涉及与"实际"对象的通信,因此代理通常充当着中间人的角色,下面是一个用来展示动态代理结构的简单示例: /** 普通(非动态)代理示例: */ interface Interface { void doSomething(); void somethingElse(String arg); } class RealObject

浅谈-Java设计模式之动态代理

动态代理模式(Dynamic Proxy Pattern): 在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface).另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的. 首先我们先来看看java的API帮助文档是怎么样对这两个类进行描述的: InvocationHandler该接口唯一方法 invoke(Object proxy, Method method, Object[] args) Object

Java设计模式—Proxy动态代理模式

代理:设计模式 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理. 图 1. 代理模式 为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别.通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性.Java 动态代理机制以巧妙的方式近乎完

JAVA设计模式之动态代理

代理:设计模式 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理. 为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别.通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性.Java 动态代理机制以巧妙的方式近乎完美地实践了代理模式的

代理模式(静态代理+动态代理)——JAVA

代理模式是常用的java设计模式,他的特征是代理类与目标类有同样的接口,代理类主要负责为目标类预处理消息.过滤消息.把消息转发给目标类,以及事后处理消息等.代理类与目标类之间通常会存在关联关系,一个代理类的对象与一个目标类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用目标类的对象的相关方法,来提供特定的服务. 结构图如下: 按照代理的创建时期,代理类可以分为静态代理和动态代理. 静态代理:由程序员创建或特定工具自动生成源代码,再对其编译.在程序运行前,代理类(Proxy)的.clas

Java学习笔记——动态代理

所谓动态,也就是说这个东西是可变的,或者说不是一生下来就有的.提到动态就不得不说静态,静态代理,个人觉得是指一个代理在程序中是事先写好的,不能变的,就像上一篇"Java学习笔记--RMI"中的远程代理,其中客户端服务对象就是一个远程服务对象的代理,这个代理可以使得客户在操作时感觉像在操作本地对象一样,远程对象对于客户是透明的.我们可以看出这里的远程代理,是在程序中事先写好的,而本节我们要讨论的远程代理,是由JVM根据反射机制,在程序运行时动态生成的.(以上是本人的理解,如果有不正确的地

细说java系统之动态代理

代理模式 在深入学习动态代理之前,需要先掌握代理模式.只有深刻理解了代理模式的应用,才能充分理解Java动态代理带来的便利. 在生活中存在许多使用"代理模式"的场景,比如:村里的张三今年已经30岁了,但是还没结婚,可把他老妈给愁坏了,于是就拜托村东头的王媒婆给儿子找个媳妇. 在这里,要娶媳妇的人是张三,但是他不能直接跑到女方家把人家闺女直接带回来,需要中间人王媒婆上门说媒,在这里王媒婆就是一个代理. 另外,我们上大学的时候都知道,学校的机房都是通过一个代理服务器上网的,因为只有一个外网

java中的动态代理机制

在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface).另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的.下面通过代码来学习java中的动态代理技术. 首先定义一个接口: package com.aop.spring; /** * Created by xinfengyao on 16-2-29. */ public interface Perform { public void play(); } 实

java反射与动态代理

Java反射与动态代理 Java反射机制可以动态地获取类的结构,动态地调用对象的方法,是java语言一个动态化的机制.java动态代理可以在不改变被调用对象源码的前提下,在被调用方法前后增加自己的操作,极大地降低了模块之间的耦合性.这些都是java的基础知识,要想成为一名合格的程序猿,必须掌握! Java反射机制 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为

设计模式之动态代理模式

设计模式之动态代理模式 代理模式: Provide a surrogate or placeholder for another object to controlaccess to it(为其他对象提供一种代理以控制对这个对象的访问).使用代理模式创建代理对象,让代理对象控制目标对象的访问(目标对象可以是远程的对象.创建开销 大的对象或需要安全控制的对象),并且可以在不改变目标对象的情况下添加一些额外的功能. 代理模式相关内容详见本人之前文章:http://www.cnblogs.com/zh