结构模式之代理模式
1 概述
代理模式(Proxy Pattern)是Javaer们最熟悉的设计模式之一,大名鼎鼎的AOP
就是通过代理模式来实现的。
2 代理模式
现实中,如果要邀请某个明星参加活动,我们不是跟这个明星直接沟通,而是找他的经纪人。因为明星只需要负责表演就可以了,其他的事情由经纪人来安排。代理模式就是类似思想的体现:构造一个代理对象作为中间层,当我们需要调用某个功能时,不是直接调用功能本身,而是通过代理对象完成请求转发。这样做的好处是:
- 实现了客户端与服务之间的解藕
- 职责分离,服务方可以只专注与自己的主逻辑,而把一些扩展的逻辑放在代理对象中去实现
3 案例
看一个例子。定义一个Audience
接口,有watchFilm()
的功能,同时定义一个实现类给予基本的实现:
public interface Audience { void watchFilm();
}
public class AudienceImpl implements Audience {
String name;
public AudienceImpl(String name) {
this.name = name;
}
[@Override](https://my.oschina.net/u/1162528)
public void watchFilm() {
System.out.println(name + " is watching film.");
}
}
在此之上,需要增加一个功能,统计观影人数。
// 模拟dao层,提供统计观影人数的方法public class StatisticDao {
private static StatisticDao instance = new StatisticDao();
AtomicLong audienceNumber = new AtomicLong();
private StatisticDao(){};
public void incrAudienceNumber() {
audienceNumber.getAndIncrement();
}
public void showAudienceNumber() {
System.out.println(audienceNumber.get() + " audiences have watched the film.");
}
public static StatisticDao newInstance() {
return instance;
}
}
最简单的做法当然是直接在AudienceImpl
类里面做修改。但是严格来说,统计观影人数和看电影是两个功能,这违反了单一职责原则。而且如果以后需要增加其他功能,还是需要修改类本身,不易于维护。
如果使用代理模式,能很好地解决这个问题。
3.1 静态代理
给AudienceImpl
定义一个代理对象,把统计观影人数的功能放在代理对象中来做:
public class Test { public static void main(String[] args) {
// 获取的是代理类
Audience nightField = new AudienceProxy(new AudienceImpl("Night Field"));
Audience rocky = new AudienceProxy(new AudienceImpl("Rocky"));
nightField.watchFilm();
rocky.watchFilm();
StatisticDao.newInstance().showAudienceNumber();
}
}
// Proxy需要实现和 被代理类 相同的接口
public class AudienceProxy implements Audience {
// 持有被代理对象
Audience targetAudience;
StatisticDao statisticDao = StatisticDao.newInstance();
AudienceProxy(Audience targetAudience) {
this.targetAudience = targetAudience;
}
[@Override](https://my.oschina.net/u/1162528)
public void watchFilm() {
// 接口的实现,其实就是调用了被代理类的方法
targetAudience.watchFilm();
// 额外增加了统计人数的功能
statisticDao.incrAudienceNumber();
}
}
输出:
Night Field is watching film.Rocky is watching film.
2 audiences have watched the film.
上述例子是静态代理的实现方式,通过增加一个代理对象,在不修改原有逻辑的情况下,新增了功能。
但是静态代理有一个弊端,就是代理对象是静态的class
无法动态扩展。更常见的例子是,需要在工程中某些特定类的方法前后添加log
,如果用静态代理的方法来实现的话,需要给所有的这些类都新建一个代理对象,这个工作量无疑是巨大的。于是动态代理应运而生。(使用AspectJ
通过编译器来实现切面模块的织入,也算是一种静态代理,但日常使用不多,本文不作考虑)。
3.2 动态代理--JDK InvocationHandler
自从JDK1.3
开始,Java
原生支持了动态代理。所谓动态代理,就是在运行时(runtime)生成代理对象。下面例子是用JDK
的动态代理来实现统计观影人数的功能:
public class Test { public static void main(String[] args) {
// 获取的是代理类
Audience nightField = new AudienceHandler(new AudienceImpl("Night Field")).getProxy();
Audience rocky = new AudienceHandler(new AudienceImpl("Rocky")).getProxy();
nightField.watchFilm();
rocky.watchFilm();
StatisticDao.newInstance().showAudienceNumber();
}
}
// Proxy实现InvocationHandler接口
public class AudienceHandler implements InvocationHandler {
// 持有被代理对象
Audience targetAudience;
StatisticDao statisticDao = StatisticDao.newInstance();
AudienceHandler(Audience targetAudience) {
this.targetAudience = targetAudience;
}
[@Override](https://my.oschina.net/u/1162528)
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 调用被代理类的方法
Object obj = method.invoke(targetAudience, args);
// 额外增加了统计人数的功能
statisticDao.incrAudienceNumber();
return obj;
}
public Audience getProxy() {
// newProxyInstance()方法,会在运行时构建出一个代理类,
// 可以看到,被代理对象的接口是方法的第二个参数,所以要求被代理对象必须实现接口
return (Audience) Proxy.newProxyInstance(targetAudience.getClass().getClassLoader(), targetAudience.getClass().getInterfaces(), this);
}
}
输出:
Night Field is watching film.Rocky is watching film.
2 audiences have watched the film.
JDK
提供了InvocationHandler
接口,可以在invoke()
方法里面自定义代理对象的逻辑,在上例中,我们额外实现了统计观影人数的功能。Proxy
类的newProxyInstance()
方法可以返回一个代理对象,需要三个参数:
- 类加载器:代理对象通过被代理对象的类加载器,在运行时动态生成。
- 被代理对象的接口:
JDK
的动态代理原理与静态代理类似,需要被代理对象实现接口,这也是此种代理方式的限制。 InvocationHandler
对象:最终代理对象调用的是InvocationHandler
的invoke()
方法。
JDK
的动态代理会在JVM
中创建类似com.sun.proxy.$Proxy0.class
的代理对象,通过反编译可以看到,实现方式跟静态代理很相似:
public final class $Proxy0 extends Proxy implements Audience { // 对应了equals(), hashcode(), toString(), watchFilm()几个方法
private static Method m1;
private static Method m0;
private static Method m3;
private static Method m2;
// InvocationHandler作为构造方法的参数传进来
public =$Proxy0(InvocationHandler var1) throws {
super(var1);
}
// equals()方法也会被代理,调用InvocationHandler调用invoke()方法
// invoke()方法中可以调用被代理对象的方法,同时可以增加额外的逻辑
public final boolean equals(Object var1) throws {
try {
return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
// hashCode()方法也会被代理,调用InvocationHandler调用invoke()方法
// invoke()方法中可以调用被代理对象的方法,同时可以增加额外的逻辑
public final int hashCode() throws {
try {
return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
// 代理类的watchFilm()方法,最终是调用InvocationHandler调用invoke()方法
// invoke()方法中可以调用被代理对象的watchFilm()方法,同时增加了统计观影人数的功能
public final void watchFilm() throws {
try {
super.h.invoke(this, m3, (Object[])null));
} catch (RuntimeException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
// toString()方法也会被代理,调用InvocationHandler调用invoke()方法
// invoke()方法中可以调用被代理对象的方法,同时可以增加额外的逻辑
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
// 静态块初始化4个方法
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m3 = Class.forName("cn.com.nightfield.patterns.structural.proxy.Audience").getMethod("watchFilm", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
JDK
的动态代理可以动态地生成代理对象,比静态代理方便得多,但是要求被代理对象必须实现接口,否则无法进行代理。对于这一类情况,CGLib(Code Generation Library)提供了解决方案。
3.3 动态代理--CGLib MethodInterceptor
CGLib
是一个强大的代码生成类库,可以用来动态扩展/创建Java
类。其底层依赖于一个Java
字节码操作框架ASM,其作者熟读JVM
规范,使得ASM
类库可以直接以二进制的形式修改类或动态生成类。
CGLib
同样提供了动态代理的实现方式:
public class Test { public static void main(String[] args) {
// 获取的是代理类
Audience nightField = new AudienceInterceptor(new AudienceImpl("Night Field")).getProxy();
Audience rocky = new AudienceInterceptor(new AudienceImpl("Rocky")).getProxy();
nightField.watchFilm();
rocky.watchFilm();
StatisticDao.newInstance().showAudienceNumber();
}
}
public class AudienceInterceptor implements MethodInterceptor {
// 持有被代理对象
Audience targetAudience;
StatisticDao statisticDao = StatisticDao.newInstance();
AudienceInterceptor(Audience targetAudience) {
this.targetAudience = targetAudience;
}
// 方法会动态生成一个代理对象,可以看到,过程中需要指定代理对象的父类
// 因为CGLib生成的动态代理,是被代理对象的子类,
public Audience getProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetAudience.getClass());
enhancer.setCallback(this);
return (Audience) enhancer.create(new Class[]{String.class}, new Object[]{ReflectUtil.getField(targetAudience, "name")});
}
[@Override](https://my.oschina.net/u/1162528)
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 调用被代理类的方法
Object ret = proxy.invokeSuper(obj, args);
// 额外增加了统计人数的功能
statisticDao.incrAudienceNumber();
return ret;
}
}
输出:
Night Field is watching film.Rocky is watching film.
2 audiences have watched the film.
用CGLib
的方式实现动态代理,需要实现MethodInterceptor
接口,并在intercept()
方法中处理额外的逻辑。因为代理对象会通过回调(Callback)的方式,来调用intercept()
方法。
通过CGLib
生成的代理对象,其实是被代理对象的一个子类,调用被代理方法时,用的是MethodProxy.invokeSuper(obj, args)
方法。所以,用CGLib
的方式实现的代理模式也是有限制的:不能代理final
修饰的类和方法,不能代理private
的方法。
通过反编译,我们也能一窥CGLib
生成代理类的真容:
// 代理对象继承了被代理对象AudienceImplpublic class AudienceImpl$$EnhancerByCGLIB$$570ee29d extends AudienceImpl implements Factory {
private boolean CGLIB$BOUND;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback[] CGLIB$STATIC_CALLBACKS;
// 我们定义的MethodInterceptor
private MethodInterceptor CGLIB$CALLBACK_0;
// 各代理方法与MethodProxy对象,除了watchFilm(),还能代理Object类中的方法
private static final Method CGLIB$watchFilm$0$Method;
private static final MethodProxy CGLIB$watchFilm$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$finalize$1$Method;
private static final MethodProxy CGLIB$finalize$1$Proxy;
private static final Method CGLIB$equals$2$Method;
private static final MethodProxy CGLIB$equals$2$Proxy;
private static final Method CGLIB$toString$3$Method;
private static final MethodProxy CGLIB$toString$3$Proxy;
private static final Method CGLIB$hashCode$4$Method;
private static final MethodProxy CGLIB$hashCode$4$Proxy;
private static final Method CGLIB$clone$5$Method;
private static final MethodProxy CGLIB$clone$5$Proxy;
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
// 代理对象
Class var0 = Class.forName("cn.com.nightfield.patterns.structural.proxy.cgLib.AudienceImpl$$EnhancerByCGLIB$$570ee29d");
Class var1;
// 初始化Object类中的方法与对应的MethodProxy对象
Method[] var10000 = ReflectUtils.findMethods(new String[]{"finalize", "()V", "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
CGLIB$finalize$1$Method = var10000[0];
CGLIB$finalize$1$Proxy = MethodProxy.create(var1, var0, "()V", "finalize", "CGLIB$finalize$1");
CGLIB$equals$2$Method = var10000[1];
CGLIB$equals$2$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2");
CGLIB$toString$3$Method = var10000[2];
CGLIB$toString$3$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$3");
CGLIB$hashCode$4$Method = var10000[3];
CGLIB$hashCode$4$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$4");
CGLIB$clone$5$Method = var10000[4];
CGLIB$clone$5$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");
// 初始化watchFilm方法与对应的MethodProxy对象
CGLIB$watchFilm$0$Method = ReflectUtils.findMethods(new String[]{"watchFilm", "()Ljava/lang/Void;"}, (var1 = Class.forName("cn.com.nightfield.patterns.structural.proxy.cgLib.AudienceImpl")).getDeclaredMethods())[0];
CGLIB$watchFilm$0$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "watchFilm", "CGLIB$watchFilm$0");
}
// 代表了被代理类的watchFilm()方法,没有额外逻辑,单纯调用watchFilm()方法
final String CGLIB$watchFilm$0() {
return super.watchFilm();
}
// 代理类中的watchFilm()方法
public final String watchFilm() {
// 我们定义的MethodInterceptor
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
// 回调方法,调用自定义的MethodInterceptor中intercept()方法
var10000.intercept(this, CGLIB$watchFilm$0$Method, CGLIB$emptyArgs, CGLIB$watchFilm$0$Proxy);
} else {
// 如果MethodInterceptor不存在,则直接调用被代理方法
super.watchFilm();
}
}
/*
* 以下Object类中的的方法与watchFilm()方法逻辑类似
*/
final void CGLIB$finalize$1() throws Throwable {
super.finalize();
}
protected final void finalize() throws Throwable {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
var10000.intercept(this, CGLIB$finalize$1$Method, CGLIB$emptyArgs, CGLIB$finalize$1$Proxy);
} else {
super.finalize();
}
}
final boolean CGLIB$equals$2(Object var1) {
return super.equals(var1);
}
public final boolean equals(Object var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
Object var2 = var10000.intercept(this, CGLIB$equals$2$Method, new Object[]{var1}, CGLIB$equals$2$Proxy);
return var2 == null ? false : (Boolean)var2;
} else {
return super.equals(var1);
}
}
final String CGLIB$toString$3() {
return super.toString();
}
public final String toString() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$3$Method, CGLIB$emptyArgs, CGLIB$toString$3$Proxy) : super.toString();
}
final int CGLIB$hashCode$4() {
return super.hashCode();
}
public final int hashCode() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
Object var1 = var10000.intercept(this, CGLIB$hashCode$4$Method, CGLIB$emptyArgs, CGLIB$hashCode$4$Proxy);
return var1 == null ? 0 : ((Number)var1).intValue();
} else {
return super.hashCode();
}
}
final Object CGLIB$clone$5() throws CloneNotSupportedException {
return super.clone();
}
protected final Object clone() throws CloneNotSupportedException {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? var10000.intercept(this, CGLIB$clone$5$Method, CGLIB$emptyArgs, CGLIB$clone$5$Proxy) : super.clone();
}
// 获取MethodProxy对象的方法
public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
String var10000 = var0.toString();
switch(var10000.hashCode()) {
case -1574182249:
if (var10000.equals("finalize()V")) {
return CGLIB$finalize$1$Proxy;
}
break;
case -508378822:
if (var10000.equals("clone()Ljava/lang/Object;")) {
return CGLIB$clone$5$Proxy;
}
break;
case 509984470:
if (var10000.equals("watchFilm()Ljava/lang/Void;")) {
return CGLIB$watchFilm$0$Proxy;
}
break;
case 1826985398:
if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
return CGLIB$equals$2$Proxy;
}
break;
case 1913648695:
if (var10000.equals("toString()Ljava/lang/String;")) {
return CGLIB$toString$3$Proxy;
}
break;
case 1984935277:
if (var10000.equals("hashCode()I")) {
return CGLIB$hashCode$4$Proxy;
}
}
return null;
}
// 构造方法,绑定callback(MethodInterceptor)
public AudienceImpl$$EnhancerByCGLIB$$570ee29d() {
CGLIB$BIND_CALLBACKS(this);
}
public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
CGLIB$THREAD_CALLBACKS.set(var0);
}
public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
CGLIB$STATIC_CALLBACKS = var0;
}
// 绑定callback(MethodInterceptor)
private static final void CGLIB$BIND_CALLBACKS(Object var0) {
AudienceImpl$$EnhancerByCGLIB$$570ee29d var1 = (AudienceImpl$$EnhancerByCGLIB$$570ee29d)var0;
if (!var1.CGLIB$BOUND) {
var1.CGLIB$BOUND = true;
Object var10000 = CGLIB$THREAD_CALLBACKS.get();
if (var10000 == null) {
var10000 = CGLIB$STATIC_CALLBACKS;
if (var10000 == null) {
return;
}
}
var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
}
}
public Object newInstance(Callback[] var1) {
CGLIB$SET_THREAD_CALLBACKS(var1);
AudienceImpl$$EnhancerByCGLIB$$570ee29d var10000 = new AudienceImpl$$EnhancerByCGLIB$$570ee29d();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Callback var1) {
CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
AudienceImpl$$EnhancerByCGLIB$$570ee29d var10000 = new AudienceImpl$$EnhancerByCGLIB$$570ee29d();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
CGLIB$SET_THREAD_CALLBACKS(var3);
AudienceImpl$$EnhancerByCGLIB$$570ee29d var10000 = new AudienceImpl$$EnhancerByCGLIB$$570ee29d;
switch(var1.length) {
case 0:
var10000.<init>();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
default:
throw new IllegalArgumentException("Constructor not found");
}
}
public Callback getCallback(int var1) {
CGLIB$BIND_CALLBACKS(this);
MethodInterceptor var10000;
switch(var1) {
case 0:
var10000 = this.CGLIB$CALLBACK_0;
break;
default:
var10000 = null;
}
return var10000;
}
public void setCallback(int var1, Callback var2) {
switch(var1) {
case 0:
this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
default:
}
}
public Callback[] getCallbacks() {
CGLIB$BIND_CALLBACKS(this);
return new Callback[]{this.CGLIB$CALLBACK_0};
}
public void setCallbacks(Callback[] var1) {
this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
}
static {
CGLIB$STATICHOOK1();
}
}
对比JDK
,CGLib
产生的代理对象相对繁杂,但细看下,两者的思路都是一样的:代理对象实现/重写被代理对象对象中的方法,并回调InvocationHandler
/MethodInterceptor
中自定义的逻辑,调用被代理方法。
除了代理对象,CGLib
同时还会生成一系列FastClass
。JDK
的动态代理是通过反射的方式去调用被代理方法的,而众所周知,反射调用的性能并不好。所以为了避免反射,CGLib
提供了FastClass
机制(反正我能动态生成对象,索性一次生成多一些额外的对象来提高性能)。FastClass
为各个方法构建了索引,访问被代理对象的方法时,只需按索引查找,即可快速调用,方式大致如下:
public class MethodProxy { // 通过invokeSuper调用被代理方法
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
init();
// 获取FastClass
FastClassInfo fci = fastClassInfo;
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
private static class FastClassInfo {
FastClass f1; // 被代理对象对应的FastClass
FastClass f2; // 代理对象对应的FastClass
int i1; // 被代理方法对应的index
int i2; // 代理方法对应的index
}
}
public class TargetInterfaceImpl$$FastClassByCGLIB$$d18f5d8e extends FastClass {
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
AudienceImpl var10000 = (AudienceImpl)var2;
int var10001 = var1;
try {
// 各方法以索引的形式被管理
switch(var10001) {
case 0:
// 根据索引,直接调用对应的方法,可以绕开反射
var10000.watchFilm();
return null;
case 1:
var10000.wait();
return null;
case 2:
var10000.wait(((Number)var3[0]).longValue(), ((Number)var3[1]).intValue());
return null;
case 3:
var10000.wait(((Number)var3[0]).longValue());
return null;
case 4:
return new Boolean(var10000.equals(var3[0]));
case 5:
return var10000.toString();
case 6:
return new Integer(var10000.hashCode());
case 7:
return var10000.getClass();
case 8:
var10000.notify();
return null;
case 9:
var10000.notifyAll();
return null;
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
}
相对于JDK
,CGLib
由于FastClass
机制的存在,在生成代理的过程中,效率较低;但在生成代理之后,代理过程的执行效率会更高。
4 Spring AOP
通过上面的分析,可以大致猜想出Spring
的AOP
到底是怎么实现的了。InvocationHandler
和MethodInterceptor
使得我们很方便地在方法的特定位置添加如事务,日志等切面逻辑(Before
,After
,Around
,AfterThrowing
,AfterReturning
)。Spring
中对两种方式的动态代理都有实现:
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { [@Override](https://my.oschina.net/u/1162528)
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// 一般我们会通过配置 proxyTargetClass 来控制使用JDK还是CGLib,默认是false,也就是使用JdkDynamicAopProxy
// 因为运行时CGLib的效率相对于JDK会略高,所以叫 isOptimize()
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
// 如果目标类是接口,依然会用JDK动态代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// CGLib代理
return new ObjenesisCglibAopProxy(config);
}
else {
// JDK代理
return new JdkDynamicAopProxy(config);
}
}
}
下面简单举例JdkDynamicAopProxy
:
// 实现类InvocationHandler接口final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 切面逻辑委托给MethodInvocation来实现
MethodInvocation invocation;
TargetSource targetSource = this.advised.targetSource;
Class<?> targetClass = null;
Object target = null;
try {
...
Object retVal;
// 被代理类
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}
// 得到方法的interception chain,即切面列表
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {
// 直接调用目标方法
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
else {
// 通过ReflectiveMethodInvocation,来链式调用切面逻辑
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 执行切面逻辑,与被代理类的主逻辑,并得到返回值
retVal = invocation.proceed();
}
...
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// 多线程控制
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// 多线程控制
AopContext.setCurrentProxy(oldProxy);
}
}
}
}
4 总结
代理模式分为静态代理和动态代理,动态代理又有两种实现方式:JDK
和CGLib
。代理模式是AOP
的基础,是面向对象设计中非常重要的一种设计模式。
文中例子的github地址
以上是 结构模式之代理模式 的全部内容, 来源链接: utcz.com/z/515558.html