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等
JAVA设计模式——代理(动态代理)的更多相关文章
- Java设计模式—Proxy动态代理模式
代理:设计模式 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理. 图 1. 代 ...
- Java设计模式之动态代理
关于Proxy: 1,他是所有动态代理的父类: 2,他可以用作创建动态代理类和动态代理对象: 3,JDK中自带的动态代理. 1,首先创建一个接口,方法申明如下: package com.proxy; ...
- java设计模式之动态代理的概述和实现
概述 1.代理:本来应该自己做的事情,请了别人来做,被请的人就是代理对象. 举例:春节回家买票让人代买 2.在Java中java.lang.reflect包下提供了一个Proxy类和一个Invocat ...
- java 笔记(3) —— 动态代理,静态代理,cglib代理
0.代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口. 代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等. 代理类与委托类之间通常会存 ...
- 细说java系统之动态代理
代理模式 在深入学习动态代理之前,需要先掌握代理模式.只有深刻理解了代理模式的应用,才能充分理解Java动态代理带来的便利. 在生活中存在许多使用"代理模式"的场景,比如:村里的张 ...
- Java设计模式学习记录-代理模式
代理模式 代理模式是常见设计模式的一种,代理模式的定义是:为其他对象提供一种代理以控制对这个对象的访问. 在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起 ...
- 杨晓峰-Java核心技术-6 动态代理 反射 MD
目录 第6讲 | 动态代理是基于什么原理? 典型回答 考点分析 知识扩展 反射机制及其演进 动态代理 精选留言 Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAnd ...
- 十分钟理解Java中的动态代理
十分钟理解 Java 中的动态代理 一.概述 1. 什么是代理 我们大家都知道微商代理,简单地说就是代替厂家卖商品,厂家“委托”代理为其销售商品.关于微商代理,首先我们从他们那里买东西时通常不知道 ...
- 一文读懂Java中的动态代理
从代理模式说起 回顾前文: 设计模式系列之代理模式(Proxy Pattern) 要读懂动态代理,应从代理模式说起.而实现代理模式,常见有下面两种实现: (1) 代理类关联目标对象,实现目标对象实现的 ...
- java反射和动态代理实现与原理详细分析
关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式--代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理和动态代理. 一.代理模式 代理模式是常用的java设计模式, ...
随机推荐
- 人脸识别&ORC的Demo
一.用到的jar包: face_sdk-1.3.4.jar json-20160810.jar ocr_sdk-1.3.4.jar 下载地址:https://files.cnblogs.com/fil ...
- 改变input的值不会触发change事件的解决思路
通常来说,如果我们自己通过 value 改变了 input 元素的值,我们肯定是知道的,但是在某些场景下,页面上有别的逻辑在改变 input 的 value 值,我们可能希望能在这个值发生变化的时候收 ...
- ②萨克斯,音符的悠扬(Session管理)
一.前言 小朽不才,最近喜欢上了萨克斯,一年计划[传送门]中的实行.就伴随着一首萨克斯,整理了下Session管理和Session四种技术. 保存状态: #网址重写(URL rewriting) #隐 ...
- 微信支付之手机H5支付实践
最近项目中支付部分涉及到微信支付,使用的是h5支付,官方文档中是没有demo的,所以摸着石头过河,将踩过的坑记录如下. 一 应用场景 H5支付是指商户在微信客户端外的移动端网页展示商品或服务,用户在前 ...
- [NewLife.XCode]高级查询(化繁为简、分页提升性能)
NewLife.XCode是一个有10多年历史的开源数据中间件,支持nfx/netcore,由新生命团队(2002~2019)开发完成并维护至今,以下简称XCode. 整个系列教程会大量结合示例代码和 ...
- 【原创】c++拷贝初始化和直接初始化的底层区别
说明:如果看不懂的童鞋,可以直接跳到最后看总结,再回头看上文内容,如有不对,请指出~ 环境:visual studio 2013(编译器优化关闭) 源代码 下面的源代码修改自http://blog.c ...
- 一篇文章让你成为 NIO 大师 - MyCAT通信模型
这篇文章没有详细介绍 NIO 的概念,对于 NIO 不了解的同学,可根据自己需要,阅读这篇介绍 NIO 的博客 io.mycat.net.NIOAcceptor NIOAcceptor负责处理客 ...
- go跨平台编译
go语言支持直接编译不同系统的可执行程序,例如可以直接在mac上可以直接编译linux的执行程序 支持的环境变量 GOOS:目标可执行程序运行操作系统,支持 darwin,freebsd,linux, ...
- Java设计模式学习记录-观察者模式
前言 观察者模式也是对象行为模式的一种,又叫做发表-订阅(Publish/Subscribe)模式.模型-视图(Model/View)模式. 咱们目前用的最多的就是各种MQ(Message Queue ...
- [转]简单科普私钥、地址、助记词、Keystore的区别
本文转自:https://www.jianshu.com/p/d0a4a44685d3 很多人保管不好自己的虚拟财产,发生丢币的情况,很多都是因为不清楚私钥的概念. 私钥(Private Key) 比 ...