java的静态代理和动态代理(jdk、cglib)
一、代理模式
代理的概念来自于设计模式中的代理模式,先了解一下代理模式
1、结构图

2、参与者
Subject:接口,定义代理类和实际类的共用接口
RealSubject:实际类,实现Subject这个接口
Proxy:代理类,实现Subject这个接口,内部引用一个RealSubject实际类
3、描述
Proxy实现了Subject接口,内部引用一个RealSubject实际类,RealSubject能做的Proxy都会
于是Proxy代替了RealSubject,实例化到Subject里交给客户端调用,而客户端不知道自己实际用的是谁
客户端调用了Subject接口中的Request()方法,实际上访问的是Proxy
Proxy类提供了一个客户端对RealSubject的间接性访问的过程,在这个过程中可以做很多的控制
4、意图
控制对象的访问
5、应用场景
虚代理:根据需要来创建开销很大的对象,该对象只有在需要的时候才会被真正创建
远程代理:用来在不同的地址空间上代表同一个对象,这个不同的地址空间可以是在本机,也可以在其他机器上,在java里面最典型的就是RMI技术
copy-on-write代理:在客户端操作的时候,只有对象确实改变了,才会真的拷贝(或克隆)一个目标对象,算是虚代理的一个分支
保护代理:控制对原始对象的访问,如果有需要,可以给不同的用户提供不同的访问权限,以控制他们对原始对象的访问
Cache代理:为那些昂贵操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果
防火墙代理:保护对象不被恶意用户访问和操作
同步代理:使多个用户能够同时访问目标对象而没有冲突
二、静态代理
java中的静态代理就是代理模式最简单的实现,下面是示例代码:
//接口
public interface Subject {
void Request();
} //实际类
public class RealSubject implements Subject {
public void Request() {
System.out.println("执行具体的功能");
}
} //代理类
public class Proxy implements Subject {
private Subject realSubject = null; public Proxy(Subject subject) {
realSubject = subject;
} public void Request() {
System.out.println("静态代理开始");
realSubject.Request();
System.out.println("静态代理结束");
}
} //客户端
public class Client {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
realSubject.Request(); Subject subject = new Proxy(realSubject);
subject.Request();
}
}
执行的结果是:

静态代理的局限:
一个代理类Proxy只能服务Subject一种接口,如果有10个不同类型的对象,需要创建10个代理类,类的数量激增、也增加了代码的冗余
如果只用一个代理类,就能完成全部的代理功能就好了,于是就有了动态代理
三、动态代理
静态代理的代码,在编译后就生成了代理类的.class字节码文件,所以在程序运行以前,代理类和实际类的关系就确定了
而动态代理不同,代理类的字节码是在程序运行期间,由JVM根据反射等机制动态生成的,代理类和实际类的关系是在程序运行时确定的
依托反射等机制,动态代理可以动态生成任意类型的代理类,一个代理的处理程序就可以处理多种对象,程序更加的灵活,也更容易扩展
spring的AOP、RMI远程代理就是依靠动态代理来实现的
java中的动态代理有两种,一种是java自带的jdk动态代理,一种是基于cglib的动态代理
1、jdk动态代理
jdk1.3开始,java语言提供了对动态代理的支持,主要会使用到java.lang.reflect包下的Proxy和InvocationHandler类
(1)、Proxy
Proxy类提供了用于创建动态代理类和实例对象的方法,它是所创建的动态代理类的父类
其中newProxyInstance()方法用来获得动态生成的代理类实例,第一个参数是实际类的类加载器,第二个参数是实际类的接口列表,第三个参数是代理处理程序类
(2)、InvocationHandler
InvocationHandler接口是代理处理程序类的实现接口,每一个被生成的代理类实例都可以提供一个相关的代理处理程序类,代理类实例的方法被调用时会回调invoke()方法
invoke()方法用来处理代理类实例的方法调用并返回结果,实现自己的代理逻辑,第一个参数是代理类实例,第二个参数是需要代理的方法,第三个参数是方法的参数数组
//接口
public interface Subject {
void Request();
} //实际类
public class RealSubject implements Subject {
public void Request() {
System.out.println("执行具体的功能");
}
} import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; //代理处理程序类
public class ProxyHandler implements InvocationHandler { private Object target; public ProxyHandler(Object target) {
this.target = target;
} @Override
public Object invoke(Object proxy, Method method, Object[] param) throws Throwable {
System.out.println("jdk动态代理开始");
Object result = method.invoke(target, param);
System.out.println("jdk动态代理结束"); return result;
}
} import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy; //客户端
public class Client {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject(); InvocationHandler handler = new ProxyHandler(realSubject);
Subject subject = (Subject)Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), handler); subject.Request();
}
}
执行的结果是:

通过"realSubject.getClass().getInterfaces()"这句可以看到,jdk动态代理的实现是依赖接口的
如果是抽象类或者一般的类需要进行代理,jdk动态代理就无法满足了,只有使用cglib动态代理
2、cglib动态代理
cglib是一个强大的高性能的代码生成包,广泛的被许多AOP的框架使用,它的开源地址在https://github.com/cglib/cglib
通过它实现动态代理,主要用到import net.sf.cglib.proxy包下的MethodInterceptor、MethodProxy和Enhancer类
(1)、MethodInterceptor
MethodInterceptor类是方法拦截器,代理类实例的方法被调用时会回调MethodInterceptor的intercept()方法拦截,用来实现自己的代理逻辑,类似于jdk动态代理的InvocationHandler接口
(2)、MethodProxy
MethodProxy是intercept()方法中的第四个参数的类型,它是实际类方法的代理引用,使用methodProxy比使用jdk自身的method在效率上会有提升
(3)、Enhancer
Enhancer用来动态创建实际类子类的代理类实例,setSuperclass()方法设置实际类为父类,setCallback()方法建立方法回调,create()方法创建一个代理类实例
//实际类
public class RealSubject {
public void Request() {
System.out.println("执行具体的功能");
} public final void RequestFinal() {
System.out.println("执行具体的功能(final)");
}
} import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy; //方法拦截器
public class ProxyInterceptor implements MethodInterceptor {
public Object intercept(Object proxy, Method method, Object[] params, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib动态代理开始");
Object result = methodProxy.invokeSuper(proxy, params);
System.out.println("cglib动态代理开始"); return result;
} //创建代理类实例
public Object newProxy(Object target)
{
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
} //客户端
public class Client {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject(); ProxyInterceptor proxyInterceptor = new ProxyInterceptor();
RealSubject subject = (RealSubject)proxyInterceptor.newProxy(realSubject); subject.Request();
subject.RequestFinal();
}
}
执行的结果是:

通过输出的结果可以发现final的方法cglib是无法处理的,因为cglib是基于继承的代理,final的方法无法被重写
3、jdk、cglib动态代理的区别
jdk动态代理是由java内部的反射机制生成一个实现代理接口的匿名类,被代理的类必须要实现一个接口,如果某个类没有实现接口则不能生成代理对象,实际使用中会有一些局限性
cglib动态代理底层是借助asm来实现的,加载实际类的.class文件,修改其字节码生成子类来处理,比java反射效率要高一些,不过生成子类的方式也带来小问题:目标类不能声明成final,因为final类不能被继承,无法生成代理;目标方法也不能声明成final,final方法不能被重写,无法得到处理
在实际使用中cglib的应用更加广泛,效率更有优势
实例代码地址:https://github.com/ctxsdhy/cnblogs-example
java的静态代理和动态代理(jdk、cglib)的更多相关文章
- 【Java】代理模式,静态代理和动态代理(基于JDK或CGLib)
当我们需要在一个方法之前或之后添加一段逻辑时,自然会想到使用代理类.代理类帮我们代理了实际类的调用,然后可以在实际调用之前和之后添加一些逻辑,从而不浸入实际类. 拓展:由于代理类能在实际类调用之前和之 ...
- 【Java】代处理?代理模式 - 静态代理,动态代理
>不用代理 有时候,我希望在一些方法前后都打印一些日志,于是有了如下代码. 这是一个处理float类型加法的方法,我想在调用它前打印一下参数,调用后打印下计算结果.(至于为什么不直接用+号运算, ...
- Java:静态代理 and 动态代理
代理模式是常用的设计模式,其特征是代理类与委托类具有相同的接口,在具体实现上,有静态代理和动态代理之分.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并 ...
- java静态代理与动态代理简单分析
原创作品,可以转载,但是请标注出处地址http://www.cnblogs.com/V1haoge/p/5860749.html 1.动态代理(Dynamic Proxy) 代理分为静态代理和动态代理 ...
- Java静态代理和动态代理
今天介绍一下代理设计模式,在业务场景中使用代理模式的好处有很多,包括什么权限校验,事务管理等等,具体有什么好处大家自动百度吧,我这里只解释代理模式的设计原理.首先这个设计模式出来的时候先是静态代理模式 ...
- Java 静态代理与动态代理
代理模式 设想你的项目依赖第三方,但是你需要对其接口做一些数据检验.性能数据记录.异常处理等,合适的方法就是使用设计模式里的代理模式. 代理模式是常用的java设计模式,代理类与委托类有同样的接口,代 ...
- java之静态代理和动态代理
我们以几个问题,来开始我们今天的学习,如果下面几个问题,你都能说出个一二,那么恭喜你,你已经掌握了这方面的知识.1,什么是代理模式?2,Java中,静态代理与动态代理的区别?3,Spring使用的是J ...
- Java中的代理模式--静态代理和动态代理本质理解
代理模式定义:为其他对象提供了一种代理以控制对这个对象的访问. 代理模式的三种角色: Subject抽象主题角色:抽象主题类可以是抽象类也可以是接口,是一个最普通的业务类型定义,无特殊要求. Real ...
- java代理:静态代理和动态代理
一.Java中有一个设计模式是代理模式 代理模式是常用的Java设计模式,特征是代理类与委托类有相同的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等. 代理类 ...
随机推荐
- Linux学习笔记-Ubuntu添加右键菜单打开终端
1.进入个人目录(如/home/batsing,下文缩写成 ~ ):设置显示隐藏文件,或使用命令行:2.进入 ~/.gnome2/nautilus-scripts 文件夹,新建一个文件,名为 term ...
- 领导让我重新做一个微信H5页面!
leader:我们需要做一个微信H5页面,效果如图,功能如描述,时间越快越好. 需求是不是很简单呢?2015-11-24 12:44:00文末有最新更新 背景描述 前几天微信转发相关项目开发后,这是第 ...
- java中的集合和数组
数组Array和集合的区别: (1)数组是大小固定的,并且同一个数组只能存放类型一样的数据(基本类型/引用类型) (2)JAVA集合可以存储和操作数目不固定的一组数据. (3)若程序时不知道究竟需要多 ...
- 屠龙之路_狭路相逢勇者胜_EighthDay
屠龙天团的少年们追着Alpha恶龙沿路留下的粪便,一路狂奔追到了福州大学生活区三十号楼4层活动室,空气中弥漫着恶龙的臭味!屠龙少年对恶龙的隐身遁迹之术心知肚明,于是点头示意,四下散开.各自拿出了电脑, ...
- 十天冲刺---Day3
站立式会议 站立式会议内容总结: git上Issues新增内容: 燃尽图 照片 组长情绪爆炸是很可怕的事情.这里自责一下. 进度缓慢是一件非常头疼的事情.还有每个人的时间都很紧张,除了学习,还有各种工 ...
- Beta版本冲刺Day3
会议讨论: 628:已经将原本写在jsp中的所有界面修饰代码转移到了css文件中,同时当页面跳转的时候也不会出现崩溃的现象,并且已经解决了上次无法连接数据库的问题.但是又遇到了一些新的小问题,希望明天 ...
- extjs的一些简单动画1
Ext.Element 类也定义了部分动画函数.我们先来看看Ext.Fx 类中的重要方法. 1.slideIn ( [String anchor], [Object options] ): 功能:滑入 ...
- jQuery基础--样式篇(3)
1.jQuiery对象与DOM对象 对于刚刚接触jQuery的初学者,我们要清楚认识一点:jQuery对象与DOM对象是不一样的.可能一时半会分不清楚哪些是jQuery对象,哪些是DOM对象,下面重点 ...
- Elasticsearch: Indexing SQL databases. The easy way
Elasticsearchis a great search engine, flexible, fast and fun. So how can I get started with it? Thi ...
- [转]响应式WEB设计学习(3)—如何改善移动设备网页的性能
原文地址:http://www.jb51.net/web/70362.html 前言 移动设备由于受到带宽.处理器运算速度的限制,因而对网页的性能有更高的要求.究竟是网页中的何种元素拉低了网页在移动设 ...