Java代理模式汇总
简介
代理模式即Proxy Pattern,23种java常用设计模式之一。其定义为:对其他对象提供一种代理以控制对这个对象的访问。
UML类图

静态代理
目标接口
public interface Subject {
public void execute();
}
目标实现类
public class RealSubject implements Subject {
private String a;
public RealSubject(String a) {
this.a = a;
}
@Override
public void execute() {
System.out.println("do biz, " + a);
}
}
代理类
public class StaticProxy implements Subject {
private Subject subject;
public StaticProxy(Subject subject) {
this.subject = subject;
}
@Override
public void execute() {
System.out.println("before executing");
subject.execute();
System.out.println("after executing");
}
}
测试类
public class StaticProxyTest {
public static void main(String[] args) {
Subject subject = new RealSubject("hello");
StaticProxy proxy = new StaticProxy(subject);
proxy.execute();
}
}
运行结果输出
before executing
do biz, hello
after executing
通过这种方法,利用代理类在目标类执行核心方法前后添加了相应辅助逻辑。

但值得注意的是,当在代码阶段规定这种代理关系,StaticProxy类通过编译器编译成.class文件,当系统运行时,此.class已经存在了。这种静态的代理模式固然在访问无法访问的资源,增强现有的接口业务功能方面有很大的优点,但是大量使用这种静态代理,会使我们系统内类的规模增大,且不易维护;并且由于StaticProxy和RealSubject的功能本质上是相同的,StaticProxy只是起到了中介的作用,这种代理在系统中的存在,会导致系统结构比较臃肿和松散。
JDK动态代理
JDK从1.3版本起自带的动态代理机制由java.lang.reflect.Proxy实现,使用时必须创建一个实现了java.lang.reflect.InvocationHandler接口的动态代理类,该接口只有一个方法:
Object invoke(Object proxy,
Method method,
Object[] args)
throws Throwable
参数:
proxy - 在其上调用方法的代理实例method - 对应于在代理实例上调用的接口方法的 Method 实例。
Method 对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。
args - 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null。基本类型的参数被包装在适当基本包装器类(如 java.lang.Integer 或 java.lang.Boolean)的实例中。
动态代理工作的基本模式就是将自己的方法功能的实现交给 InvocationHandler角色,外界对Proxy角色中的每一个方法的调用,Proxy角色都会交给InvocationHandler来处理,而InvocationHandler则调用具体对象角色的方法。如下图所示:

再来看Proxy如何创建出一个代理对象,常用的方法为:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException 参数:loader- 定义代理类的类加载器interfaces- 代理类要实现的接口列表h- 指派方法调用的调用处理程序该方法返回的对象是实现了参数interfaces中指明的接口的子类对象,因此强制要求目标类必须是接口。 接下来通过示例代码演示动态代理的使用方式 目标接口
public interface Subject {
public void doBiz();
}
目标实现类
public class RealSubject implements Subject {
private String a;
public RealSubject(String a) {
this.a = a;
}
@Override
public void doBiz() {
System.out.println("do biz, " + a);
}
}
动态代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; public class DynamicProxy implements InvocationHandler { private Object target; public DynamicProxy(Object target) {
this.target = target;
} @Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("before executing");
Object result = method.invoke(target, args);
System.out.println("after executing");
return result;
} }
测试类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy; public class DynamicProxyTest { public static void main(String[] args) {
Subject subject = new RealSubject("hello");
InvocationHandler handler = new DynamicProxy(subject);
Subject proxy = (Subject) Proxy.newProxyInstance(
Subject.class.getClassLoader(), new Class[] { Subject.class },
handler); // 由于第二个参数传入了Subject.class,因此返回的代理对象实现了该接口,可以转换为Subject对象
System.out.println("proxy = " + proxy.getClass().getName());
if (proxy instanceof Proxy) {
System.out.println("proxy implements java.lang.reflect.Proxy");
}
if (proxy instanceof Subject) {
System.out.println("proxy implements Subject");
}
proxy.doBiz();
} }
运行结果输出
proxy = com.sun.proxy.$Proxy0
proxy implements java.lang.reflect.Proxy
proxy implements Subject
before executing
do biz, hello
after executing
第一行输出为代理对象的名称,第二、三行表明代理对象实现了java.lang.reflect.Proxy接口和Subject接口,后面的打印结果与静态代理时一致。
所以JDK动态代理有个显著的特点(限制):某个类必须有实现的接口,而生成的代理类也只能代理某个类接口定义的方法。下面介绍的Cglib动态代理就不存在此类限制。
Cglib动态代理
Cglib是一个第三方类库,用于创建动态代理,包括Spring AOP在内多个框架都内部集成了Cglib,而它底层也利用了ASM操纵字节码。Cglib类库的框架图如下:

使用Cglib创建动态代理与JDK原生的动态代理不同之处在于它并不强制要求目标类为接口,因此可以对于普通Java类进行代理。
使用时需要在pom.xml配置两个依赖:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
<version>3.3.1</version>
</dependency>
动态代理类需要实现net.sf.cglib.proxy.MethodInterceptor接口(等价于JDK动态代理中的InvocationHandler接口),其中只有一个方法:
public Object intercept(Object object, Method method, Object[] args,
MethodProxy proxy) throws Throwable
参数:
object - 被代理的对象。
method - 被代理对象的方法。
args - 包含传入代理实例上方法调用的参数值的对象数组。
proxy - 代理对象。
接下来通过示例代码演示Cglib动态代理的使用方式
目标类
public class RealSubject {
private String a;
public RealSubject(String a) {
this.a = a;
}
public void doBiz() {
System.out.println("do biz, " + a);
}
}
代理类
import java.lang.reflect.Method; import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy; public class CglibProxy implements MethodInterceptor { @Override
public Object intercept(Object object, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("before executing");
Object result = proxy.invokeSuper(object, args);
System.out.println("after executing");
return result;
} }
目标类工厂
import net.sf.cglib.proxy.Enhancer;
public class RealSubjectFactory {
public static RealSubject getInstance(CglibProxy proxy) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(RealSubject.class);
enhancer.setCallback(proxy);
RealSubject subject = (RealSubject) enhancer.create(
new Class[] { String.class }, new Object[] { "hello" }); // 返回值是RealSubject的子类对象;如果目标类的构造方法不含参数,则这儿无需传入create()方法的参数
return subject;
}
}
测试类
public class CglibProxyTest {
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
RealSubject subject = RealSubjectFactory.getInstance(proxy);
subject.doBiz();
}
}
运行结果输出
before executing
do biz, hello
after executing
输出结果与静态代理一致。
Javassist动态代理
此外,利用javassist字节码生成框架也可以以类似的方式实现动态代理,使用时需要在pom.xml配置依赖:
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.18.1-GA</version>
</dependency>
接下来直接展示示例代码。
目标接口
public interface Subject {
public void doBiz();
}
目标实现类
public class RealSubject implements Subject {
private String a;
public RealSubject(String a) {
this.a = a;
}
@Override
public void doBiz() {
System.out.println("do biz, " + a);
}
}
代理类
import java.lang.reflect.Method;
import javassist.util.proxy.MethodHandler;
public class JavassistProxy implements MethodHandler {
private Object target;
public JavassistProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Method method2,
Object[] args) throws Throwable {
System.out.println("before executing");
Object result = method.invoke(target, args);
System.out.println("after executing");
return result;
}
}
测试类
import javassist.util.proxy.ProxyFactory;
import javassist.util.proxy.ProxyObject; public class JavassistProxyTest { public static void main(String[] args) throws InstantiationException,
IllegalAccessException {
Subject subject = new RealSubject("hello");
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setInterfaces(new Class[] { Subject.class });
Subject proxy = (Subject) proxyFactory.createClass().newInstance();
((ProxyObject) proxy).setHandler(new JavassistProxy(subject));
proxy.doBiz();
} }
运行结果输出
before executing
do biz, hello
after executing
输出结果与静态代理一致。
REFERENCES
[1] http://jnb.ociweb.com/jnb/jnbNov2005.html
[2] http://www.cnblogs.com/flyoung2008/archive/2013/08/11/3251148.html
[3] http://www.cnblogs.com/xiaoluo501395377/p/3383130.html
[4] http://blog.csdn.net/dreamrealised/article/details/12885739
[5] http://blog.csdn.net/jackiehff/article/details/8621517
[6] https://dzone.com/articles/cglib-missing-manual
[7] http://www.360doc.com/content/14/0801/14/1073512_398598312.shtml
[8] http://javatar.iteye.com/blog/814426
为尊重原创成果,如需转载烦请注明本文出处:http://www.cnblogs.com/fernandolee24/p/6182924.html ,特此感谢
Java代理模式汇总的更多相关文章
- Java代理模式
java代理模式及动态代理类 1. 代理模式 代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目 ...
- Java代理模式示例程序
Java代理模式示例程序 当然不是我想出来的,是我看的一个网上教程里的. 模拟的是一个对电脑公司的代理 真实类的接口: public interface SaleComputer { public S ...
- java 代理模式 总结
1.前言 最近舍友去面试遇到了关于java代理模式的问题. 我虽然知道怎么使用,但是没有做过正经的总结,因此有了这篇随笔,好好总结一下三大代理模式底层原理. 事实上,在开发项目的时候,基本用不上代理, ...
- 浅谈java代理模式
讲解java代理模式 目录 讲解java代理模式 何谓代理模式 静态代理 动态代理 JDK动态代理 CGLIB动态代理 何谓代理模式 代理模式,即Proxy Pattern,23种java常用设计模式 ...
- Java代理模式/静态代理/动态代理
代理模式:即Proxy Pattern,常用的设计模式之一.代理模式的主要作用是为其他对象提供一种代理以控制对这个对象的访问. 代理概念 :为某个对象提供一个代理,以控制对这个对象的访问. 代理类和委 ...
- JAVA代理模式与动态代理模式
1.代理模式 所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用.代理模式给某 ...
- java 代理模式一: 静态代理
代理模式: 代理模式的作用:为其他对象提供一种代理以控制对 特定对象 的访问. 某种情况下,一个客户不想或者直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用:通过代理对象引用. ...
- 18 java 代理模式 (转)
静态代理 1.新建一个接口,这个接口所提供的方法是关于数据库操作的 public interface EmployeeDao { public void updateSalary(); } 2.建一个 ...
- JAVA 代理模式(Proxy)
1.代理模式 代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 代理模式一般涉 ...
随机推荐
- SecureCRT退出全屏方法
今天在使用SecureCRT的过程中,无意点了全屏,导致SecureCRT连接某台服务器的seesion全屏.后来想退出全屏,SecureCRT没有任何提示,上网查了一下资料说: 退出全屏的命令是AL ...
- 可编辑DIV (contenteditable="true") 在鼠标光标处插入图片或者文字
近期需开发一个DIV做的编辑器,插入表情图片可直接预览效果,仔细参考了下百度贴吧的过滤粘贴过来文件的THML代码,自己整理了下.写出来只是和大家分享下,我自己也不大懂,经过努力,幸好搞定. 蛋疼的事情 ...
- NotePad++安装和配置C/C++开发插件
NotePad++ - 安装和配置C/C++开发插件 | NotePad++ - Install and Configure plugins for develop C/C++ http://aofe ...
- Go Code
目录 备注工作空间(Workspaces)GOPATH环境变量包路径(Package Path)你的第一个程序你的第一个类库包名字(Package Name)测试集成备注 备注返回目录 此文主要是对官 ...
- data格式加载图片
html img 使用data格式加载图片 背景 这久闲来无事给一位客户测试一款体检软件,是winform结构的,其中有一个功能是需要把生成的体检报告导出为html格式.测试导出后直接在谷歌浏览器 ...
- json时间格式的互换
c#代码 public class DateTimeUtil { /// <summary> /// 把json的时间格式还原-服务端 /// </summary> /// & ...
- 不想作死系列--win7远程linux桌面之vncserver
1.在linux服务器上安装vncserver yum install vncserver 或者下载相应linux版本的tigervnc-serverrpm rpm -ivh tigervnc-ser ...
- 工具条OutLookBar
工具条OutLookBar 灰姑娘本身也有自已的优点,但是却可能因为外貌不讨人喜欢,要变成白雪公主却需要有很多勇气和决心去改变自已: 有一颗善良的心 讨人喜爱的外貌 我这里讲的是一个工具条的蜕变过程, ...
- 分享个自己做的CSDN刷下载积分软件
对于评论里有人反映说,运行完后自动关机了,我要在这解释下,不好意思了亲们,由于昨晚开这个通宵刷积分,就加了个功能,刷完所有可刷积分后自动关机省点电.今天发布的时候忘记取消了.这里给大家带来不便请大家包 ...
- Citrix 服务器虚拟化之一 网络部署Xenserver 6.2
Citrix 服务器虚拟化之一 网络部署Xenserver 6.2 思杰的XenServer®是完整的服务器虚拟化平台. XenServer软件包中包含所有你需要创建和管理部署的虚拟x86计算机上运 ...