结构模式之代理模式

编程

1 概述

代理模式(Proxy Pattern)是Javaer们最熟悉的设计模式之一,大名鼎鼎的AOP就是通过代理模式来实现的。

2 代理模式

现实中,如果要邀请某个明星参加活动,我们不是跟这个明星直接沟通,而是找他的经纪人。因为明星只需要负责表演就可以了,其他的事情由经纪人来安排。代理模式就是类似思想的体现:构造一个代理对象作为中间层,当我们需要调用某个功能时,不是直接调用功能本身,而是通过代理对象完成请求转发。这样做的好处是:

  1. 实现了客户端与服务之间的解藕
  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()方法可以返回一个代理对象,需要三个参数:

  1. 类加载器:代理对象通过被代理对象的类加载器,在运行时动态生成。
  2. 被代理对象的接口:JDK的动态代理原理与静态代理类似,需要被代理对象实现接口,这也是此种代理方式的限制。
  3. InvocationHandler对象:最终代理对象调用的是InvocationHandlerinvoke()方法。

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生成代理类的真容:

// 代理对象继承了被代理对象AudienceImpl

public 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();

}

}

对比JDKCGLib产生的代理对象相对繁杂,但细看下,两者的思路都是一样的:代理对象实现/重写被代理对象对象中的方法,并回调InvocationHandler/MethodInterceptor中自定义的逻辑,调用被代理方法。

除了代理对象,CGLib同时还会生成一系列FastClassJDK的动态代理是通过反射的方式去调用被代理方法的,而众所周知,反射调用的性能并不好。所以为了避免反射,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");

}

}

相对于JDKCGLib由于FastClass机制的存在,在生成代理的过程中,效率较低;但在生成代理之后,代理过程的执行效率会更高。

4 Spring AOP

通过上面的分析,可以大致猜想出SpringAOP到底是怎么实现的了。InvocationHandlerMethodInterceptor使得我们很方便地在方法的特定位置添加如事务,日志等切面逻辑(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 总结

代理模式分为静态代理和动态代理,动态代理又有两种实现方式:JDKCGLib。代理模式是AOP的基础,是面向对象设计中非常重要的一种设计模式。

文中例子的github地址

以上是 结构模式之代理模式 的全部内容, 来源链接: utcz.com/z/515558.html

回到顶部