介绍:
要求给某一个对象提供一个代理,并由代理对象控制原有对象的引用
角色:
Subject(抽象主题角色)
声明了真实主题和代理主题接口,这样一来,使用真实主题的地方都可以使用代理主题
Proxy(代理主题角色)
代理主题角色包含对真实主题的引用,从而可以在任何时候操作真实主题对象,代理角色通常
RealSubject(真实主题角色)
定义了代表角色所代表的对象,在真实主题主题角色中实现了真实的业务操作,客户端可以通过代理主题角色间接调用真实主题角色中定义的方法
结构图:
优点:
- 降低系统耦合度
- 远程代理使得客户端可以访问远程机器对象,远程机器可能具有更好的计算性能与处理速度,可以快速的相应并处理客户端需求
- 可以减少系统资源消耗,对系统进行优化并提高运行速度
- 保护代理可以控制对真实对象的使用权限
缺点:
- 因为在客户端和真实对象之间添加了代理对象,可能会造成处理速度更慢
- 增加额外工作,并且有些代理是非常复杂的
代理模式适用环境(按职责来划分):
远程代理:为一个不同的地址空间的对象提供一个本地代理对象,不同地址空间可以是在同一台主机上,也可以是另一台主机上
虚拟代理:如果要建立一个资源消耗较大的对象,先创建一个资源消耗较少的对象来表示,真实对象只有在需要时才会被创建
copy-on-Write代理:它是虚拟代理的一种,把复制(克隆)操作延迟到只有在客户端真正需要时才执行。一般来说,对象的深克隆是一个开销较大的操作,copy-on-Write代理可以让这个操作延迟,只有在对象再用到的时候才会被克隆
保护代理:控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限
缓冲代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果
防火墙代理:保护目标不让恶意用于接近
同步化代理:使几个用户能够同时使用一个对象而没用冲突
智能引用代理:当一个对象被引用时,提供一些额外的操作,比如将次对象调用的次数给记录下来
虚拟代理,远程代理和保护代理是最常见的代理模式
代理分类:
- 静态代理
- 动态代理(jdk动态代理,cglib动态代理)
静态代理案例:
西门庆想勾搭潘金莲,不直接找潘金莲,而是通过王婆找,
流程分析:
代码:
抽象角色类:
public interface Behavior {
void sayHello();
void haveIdea();
}
真实角色类:
public class PanJinLian implements Behavior{
@Override
public void sayHello() {
System.out.println("潘金莲在打招呼。。。。");
}
@Override
public void haveIdea() {
System.out.println("潘金莲在勾搭。。。。。");
}
}
代理角色类:
public class WangPo implements Behavior {
private Behavior behavior;
//这个地方直接定死
public WangPo(){
this.behavior = new PanJinLian();
}
public WangPo(Behavior behavior) {
this.behavior = behavior;
}
@Override
public void sayHello() {
this.behavior.sayHello();
}
@Override
public void haveIdea() {
this.behavior.haveIdea();
}
}
测试:(main方法测试)
public class XiMenQing {
public static void main(String[] args) {
WangPo wangPo = new WangPo();
wangPo.sayHello();
wangPo.haveIdea();
}
}
结果:
好处,如果西门庆想勾搭林黛玉,直接添加一个林黛玉类
public class LinDaiYu implements Behavior{
@Override
public void sayHello() {
System.out.println("林黛玉打招呼......");
}
@Override
public void haveIdea() {
System.out.println("林黛玉勾搭人......");
}
}
public class XiMenQing {
public static void main(String[] args) {
//WangPo wangPo = new WangPo();
// wangPo.sayHello();
//wangPo.haveIdea();
LinDaiYu linDaiYu = new LinDaiYu();
WangPo wangPo1 = new WangPo(linDaiYu);
wangPo1.sayHello();
wangPo1.haveIdea();
}
}
JDK动态代理和cglib动态代理区别:
(参考博文:Cglib和jdk动态代理的区别 - 橙发 - 博客园)
- jdk动态代理:利用拦截器(必须实现InvocationHandler)加反射机制生成一个代理接口匿名类,在调用具体方法之前电泳InvocationHandler进行处理
- cglib动态代理:利用ASM框架,对代理对象生成class文件加载进来,通过修改其字节码生成子类来处理
- jdk动态代理只能对实现了接口的类生成代理,而不能针对类
- cglib针对类实现了代理,主要对指定的类生成一个子类,覆盖其中方法,并覆盖其中方法的增强,因为采用的方法是继承,所以该类或方法最好不要出现final
什么时候用JDK动态代理什么时候用cglib动态代理:
- 目标对象生成接口,使用jdk动态代理
- 如果目标对象使用了接口,可以强制使用cglib代理
- 如果目标对象没有生成接口,必须采用cglib库,Spring会自动太jdk代理和cglib代理之间转化
jdk和cglib哪个更快?
cglib地城是ASM字节码生成框架,在jdk1.6以前比反射更高,后面对jdk动态代理不断优化,在1.8以后,jdk动态代理效率高于cglib动态代理.
Spring如何选择使用JDK还是cglib?
- 实现bean接口时,会使用jdk代理
- 没有实现bean接口时,会使用cglib代理
- 也可以强制使用cglib代理,(在spring配置中加入<aop:aspectj-autoproxy proxyt-target-class=”true”/>)
JDK动态代理:
主要涉及类:
InvocationHandler接口.它是代理实例的调用处理程序接口
接口方法:public Object invoke(Object proxy, Method method, Object[] args)
- 第一个参数proxy表示代理类
- 第二个参数method表示要代理的方法
- 第三个参数args表示代理方法参数数组
Proxy类:该类即为动态代理
方法:public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
newProxyInstance用于根据传入的接口类型interface返回一个动态创建的代理类实例
- 第一个参数loader表示代理类的类加载器
- 第二个参数interfaces表示代理类实现的接口列表(与真实主题类的接口列表表示一致)
- 第三个参数h表示所指派的调用处理程序类
JDK动态代理案例
介绍:
DK中的动态代理是通过反射类Proxy以及InvocationHandler回调接口实现的,但是JDK中所有要进行动态代理的类必须要实现一个接口,也就是说只能对该类所实现接口中定义的方法进行代理,这在实际编程中有一定的局限性,而且使用反射的效率也不高
抽象主题类:
public interface AbstractSubject {
public void method();
}
真实主题类:
public class RealSubjectA implements AbstractSubject{
@Override
public void method() {
System.out.println("真实主题A!");
}
}
public class RealSubjectB implements AbstractSubject {
@Override
public void method() {
System.out.println("真实主题B!");
}
}
代理类:
public class LoggerProxy implements AbstractSubject{
private BusinessClass businessClass = new BusinessClass();
@Override
public void method() {
System.out.println("method方法被调用,当前时间为:"+ LocalDateTime.now());
try {
businessClass.method();
System.out.println("方法method()调用成功!");
} catch (Exception e) {
System.out.println("方法method调用失败!");
}
}
}
测试:
public static void main(String[] args) {
InvocationHandler handler = new DynamicProxy(new RealSubjectA());
AbstractSubject subject = (AbstractSubject) Proxy.newProxyInstance(AbstractSubject.class.getClassLoader(),new Class[]{AbstractSubject.class},handler);
subject.method();
System.out.println("=================================");
InvocationHandler handler1 = new DynamicProxy(new RealSubjectB());
AbstractSubject subject1 = (AbstractSubject) Proxy.newProxyInstance(AbstractSubject.class.getClassLoader(),new Class[]{AbstractSubject.class},handler1);
subject1.method();
}
结果:
cilib动态代理:
(参考博文:设计模式-代理模式(jdk代理和cglib代理详解)_几人憔悴几人泪-CSDN博客_cglib代理模式)
介绍:
JDK动态代理机制只能代理实现接口的类,一般没有实现接口的类不能进行代理。cglib就是针对类来实现代理的,它
的原理是对指定目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进
行代理。
使用cglib实现动态代理,完全不受代理类必须实现接口的限制,而且cglib底层采用ASM字节码生成框架,使用字节码
技术生成代理类.
主要方法:public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable ;
- 第一个参数proxy为cglib动态生成的代理实例
- 第二个参数method为上文中实体类所调用的被代理的方法调用
- 第三个参数args为method参数数值列表
- 第四个参数methodProxy为生成代理类对方法的代理引用
- 返回:从代理实例方法调用返回值
案例1:
需要装备的jar:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>5.0.4</version>
</dependency>
抽象主题角色:
public interface AbstractSubject {
void delete();
}
真实主题角色:
public class RealSubject implements AbstractSubject {
@Override
public void delete() {
System.out.println("对数据进行删除");
}
}
代理主题角色:
public class CglibProxy {
/**
* 被代理对象
*/
private Object object;
public CglibProxy(Object object) {
super();
this.object = object;
}
public Object getCglibProxy(){
//Enhancer类是cglib中的一个字节码增强器,它可以方便的为你所要处理的类进行扩展
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(object.getClass());//将目标对象所在的类作为Enhancer类的父类
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object proxy, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("开始处理.....时间:"+System.currentTimeMillis());
method.invoke(object,objects);
System.out.println("结束......");
return proxy;
}
});
return enhancer.create();//生成对象并返回
}
}
测试:
public static void main(String[] args) {
//真实对象
RealSubject realSubject = new RealSubject();
//代理对象
RealSubject proxySubject= (RealSubject) new CglibProxy(realSubject).getCglibProxy();
proxySubject.delete();
}
结果:
代理主题角色(另一种写法):
public class CglibProxy2 implements MethodInterceptor {
/**
* 被代理对象
*/
private Object object;
public CglibProxy2(Object object) {
this.object = object;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("开始处理......时间:"+System.currentTimeMillis());
Object result = methodProxy.invokeSuper(o,objects);
System.out.println("结束处理......时间:"+System.currentTimeMillis());
return result;
}
}
测试:
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
CglibProxy2 cglibProxy2 = new CglibProxy2(realSubject);
//创建加强器,用来创建动态代理类
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(realSubject.getClass());
//设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
enhancer.setCallback(cglibProxy2);
RealSubject realSubject1= (RealSubject) enhancer.create();
//调用
realSubject1.delete();
}