返回介绍

7.3.3 创建代理

发布于 2025-04-22 22:09:14 字数 25969 浏览 0 评论 0 收藏

在获取了所有对应 bean 的增强器后,便可以进行代理的创建了。

protected Object createProxy(

Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource

targetSource) {

  ProxyFactory proxyFactory = new ProxyFactory();

 //获取当前类中相关属性

 proxyFactory.copyFrom(this);

 //决定对于给定的 bean 是否应该使用 targetClass 而不是他的接口代理,

 //检查 proxyTargeClass 设置以及 preserveTargetClass 属性

  if (!shouldProxyTargetClass(beanClass, beanName)) {

   // Must allow for introductions; can't just set interfaces to

   // the target's interfaces only.

Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass,&nbsp;this.proxyClassLoader);

   for (Class<?> targetInterface : targetInterfaces) {

   //添加代理接口

   proxyFactory.addInterface(targetInterface);

  }

 }

  Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);

  for (Advisor advisor : advisors) {

  //加入增强器

  proxyFactory.addAdvisor(advisor);

 }

 //设置要代理的类

 proxyFactory.setTargetSource(targetSource);

 //定制代理

 customizeProxyFactory(proxyFactory);

 //用来控制代理工厂被配置之后,是否还允许修改通知。

 //缺省值为 false(即在代理被配置之后,不允许修改代理的配置)。

 proxyFactory.setFrozen(this.freezeProxy);

  if (advisorsPreFiltered()) {

  proxyFactory.setPreFiltered(true);

 }

  return proxyFactory.getProxy(this.proxyClassLoader);

}

对于代理类的创建及处理,Spring 委托给了 ProxyFactory 去处理,而在此函数中主要是对 ProxyFactory 的初始化操作,进而对真正的创建代理做准备,这些初始化操作包括如下内容。

(1)获取当前类中的属性。

(2)添加代理接口。

(3)封装 Advisor 并加入到 ProxyFactory 中。

(4)设置要代理的类。

(5)当然在 Spring 中还为子类提供了定制的函数 customizeProxyFactory,子类可以在此函数中进行对 ProxyFactory 的进一步封装。

(6)进行获取代理操作。

其中,封装 Advisor 并加入到 ProxyFactory 中以及创建代理是两个相对繁琐的过程,可以通过 ProxyFactory 提供的 addAdvisor 方法直接将增强器置入代理创建工厂中,但是将拦截器封装为增强器还是需要一定的逻辑的。

protected Advisor[] buildAdvisors(String beanName, Object[] specificInterceptors) {

 //解析注册的所有 interceptorName

  Advisor[] commonInterceptors = resolveInterceptorNames();

  List<Object> allInterceptors = new ArrayList<Object>();

  if (specificInterceptors != null) {

  //加入拦截器

  allInterceptors.addAll(Arrays.asList(specificInterceptors));

   if (commonInterceptors != null) {

    if (this.applyCommonInterceptorsFirst) {

     allInterceptors.addAll(0, Arrays.asList(commonInterceptors));

   }

    else {

    allInterceptors.addAll(Arrays.asList(commonInterceptors));

   }

  }

 }

  if (logger.isDebugEnabled()) {

   int nrOfCommonInterceptors = (commonInterceptors != null ? commonInterceptors.

   length : 0);

  int nrOfSpecificInterceptors = (specificInterceptors != null ? specificInterceptors.

  length : 0);

   logger.debug("Creating implicit proxy for bean '" + beanName + "' with " +

   nrOfCommonInterceptors +

    " common interceptors and " + nrOfSpecificInterceptors + " specific

   interceptors");

 }

  Advisor[] advisors = new Advisor[allInterceptors.size()];

  for (int i = 0; i < allInterceptors.size(); i++) {

  //拦截器进行封装转化为 Advisor

   advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));

 }

  return advisors;

}

public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {

 //如果要封装的对象本身就是 Advisor 类型的那么无需再做过多处理

  if (adviceObject instanceof Advisor) {

   return (Advisor) adviceObject;

 }

 //因为此封装方法只对 Advisor 与 Advice 两种类型的数据有效,如果不是将不能封装

  if (!(adviceObject instanceof Advice)) {

   throw new UnknownAdviceTypeException(adviceObject);

 }

  Advice advice = (Advice) adviceObject;

  if (advice instanceof MethodInterceptor) {

  //如果是 MethodInterceptor 类型则使用 DefaultPointcutAdvisor 封装

   return new DefaultPointcutAdvisor(advice);

 }

 //如果存在 Advisor 的适配器那么也同样需要进行封装

  for (AdvisorAdapter adapter : this.adapters) {

   // Check that it is supported.

   if (adapter.supportsAdvice(advice)) {

    return new DefaultPointcutAdvisor(advice);

  }

 }

  throw new UnknownAdviceTypeException(advice);

}

由于 Spring 中涉及过多的拦截器、增强器、增强方法等方式来对逻辑进行增强,所以非常有必要统一封装成 Advisor 来进行代理的创建,完成了增强的封装过程,那么解析最重要的一步就是代理的创建与获取了。

public Object getProxy(ClassLoader classLoader) {

 return createAopProxy().getProxy(classLoader);

}

1.创建代理

protected final synchronized AopProxy createAopProxy() {

  if (!this.active) {

  activate();

 }

 //创建代理

  return getAopProxyFactory().createAopProxy(this);

}

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {

 if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxy

  Interfaces(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.");

  }

   if (targetClass.isInterface()) {

    return new JdkDynamicAopProxy(config);

  }

   if (!cglibAvailable) {

    throw new AopConfigException(

     "Cannot proxy target class because CGLIB2 is not available. " +

     "Add CGLIB to the class path or specify proxy interfaces.");

  }

   return CglibProxyFactory.createCglibProxy(config);

 }

  else {

   return new JdkDynamicAopProxy(config);

 }

}

到此已经完成了代理的创建,不管我们之前是否有阅读过 Spring 的源代码,但是都或多或少地听过对于 Spring 的代理中 JDKProxy 的实现和 CglibProxy 的实现。Spring 是如何选取的呢?网上的介绍到处都是,现在我们就从源代码的角度分析,看看到底 Spring 是如何选择代理方式的。

从 if 中的判断条件可以看到 3 个方面影响着 Spring 的判断。

optimize:用来控制通过 CGLIB 创建的代理是否使用激进的优化策略。除非完全了解 AOP 代理如何处理优化,否则不推荐用户使用这个设置。目前这个属性仅用于 CGLIB 代理,对于 JDK 动态代理(缺省代理)无效。

proxyTargetClass:这个属性为 true 时,目标类本身被代理而不是目标类的接口。如果这个属性值被设为 true,CGLIB 代理将被创建,设置方式:<aop:aspectj-autoproxy proxy-target-class="true"/>。

hasNoUserSuppliedProxyInterfaces:是否存在代理接口。

下面是对 JDK 与 Cglib 方式的总结。

如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理实现 AOP。

如果目标对象实现了接口,可以强制使用 CGLIB 实现 AOP。

如果目标对象没有实现了接口,必须采用 CGLIB 库,Spring 会自动在 JDK 动态代理和 CGLIB 之间转换。

如何强制使用 CGLIB 实现 AOP?

(1)添加 CGLIB 库,Spring_HOME/cglib/*.jar。

(2)在 Spring 配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>。

JDK 动态代理和 CGLIB 字节码生成的区别?

JDK 动态代理只能对实现了接口的类生成代理,而不能针对类。

CGLIB 是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,因为是继承,所以该类或方法最好不要声明成 final。

2.获取代理

确定了使用哪种代理方式后便可以进行代理的创建了,但是创建之前有必要回顾一下两种方式的使用方法。

(1)JDK 代理使用示例。

创建业务接口,业务对外提供的接口,包含着业务可以对外提供的功能。

public interface UserService {

 /**

  * 目标方法

  */

  public abstract void add();

}

创建业务接口实现类。

public class UserServiceImpl implements UserService {

  /* (non-Javadoc)

  * @see dynamic.proxy.UserService#add()

  */

  public void add() {

  System.out.println("--------------------add---------------");

 }

}

创建自定义的 InvocationHandler,用于对接口提供的方法进行增强。

public class MyInvocationHandler implements InvocationHandler {

 // 目标对象

  private Object target;

 /**

  * 构造方法

  * @param target 目标对象

  */

  public MyInvocationHandler(Object target) {

  super();

   this.target = target;

 }

 /**

  * 执行目标对象的方法

  */

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

  // 在目标对象的方法执行之前简单的打印一下

  System.out.println("------------------before------------------");

  // 执行目标对象的方法

   Object result = method.invoke(target, args);

  // 在目标对象的方法执行之后简单的打印一下

  System.out.println("-------------------after------------------");

   return result;

 }

 /**

  * 获取目标对象的代理对象

  * @return 代理对象

  */

  public Object getProxy() {

   return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),

    target.getClass().getInterfaces(), this);

 }

}

最后进行测试,验证对于接口的增强是否起到作用。

public class ProxyTest {

 @Test

  public void testProxy() throws Throwable {

  // 实例化目标对象

   UserService userService = new UserServiceImpl();

  // 实例化 InvocationHandler

   MyInvocationHandler invocationHandler = new MyInvocationHandler(userService);

  // 根据目标对象生成代理对象

   UserService proxy = (UserService) invocationHandler.getProxy();

  // 调用代理对象的方法

  proxy.add();

 }

}

执行结果如下:

------------------before-------------

--------------------add--------------

-------------------after--------------

用起来很简单,其实这基本上就是 AOP 的一个简单实现了,在目标对象的方法执行之前和执行之后进行了增强。Spring 的 AOP 实现其实也是用了 Proxy 和 InvocationHandler 这两个东西的。

我们再次来回顾一下使用 JDK 代理的方式,在整个创建过程中,对于 InvocationHandler 的创建是最为核心的,在自定义的 InvocationHandler 中需要重写 3 个函数。

构造函数,将代理的对象传入。

invoke 方法,此方法中实现了 AOP 增强的所有逻辑。

getProxy 方法,此方法千篇一律,但是必不可少。

那么,我们看看 Spring 中的 JDK 代理实现是不是也是这么做的呢?继续之前的跟踪,到达 JdkDynamicAopProxy 的 getProxy。

public Object getProxy(ClassLoader classLoader) {

  if (logger.isDebugEnabled()) {

   logger.debug("Creating JDK dynamic proxy: target source is " + this.

  advised.getTargetSource());

 }

  Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);

 findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);

  return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);

}

通过之前的示例我们知道,JDKProxy 的使用关键是创建自定义的 InvocationHandler,而 InvocationHandler 中包含了需要覆盖的函数 getProxy,而当前的方法正是完成了这个操作。再次确认一下 JdkDynamicAopProxy 也确实实现了 InvocationHandler 接口,那么我们就可以推断出,在 JdkDynamicAopProxy 中一定会有个 invoke 函数,并且 JdkDynamicAopProxy 会把 AOP 的核心逻辑写在其中。查看代码,果然有这样个函数:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

  MethodInvocation invocation;

  Object oldProxy = null;

  boolean setProxyContext = false;

  TargetSource targetSource = this.advised.targetSource;

  Class targetClass = null;

Object target = null;

try {

 //equals 方法的处理

  if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {

   return equals(args[0]);

 }

 //hash 方法的处理

  if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {

   return hashCode();

 }

 /*

  * Class 类的 isAssignableFrom(Class cls) 方法:

  * 如果调用这个方法的 class 或接口 与 参数 cls 表示的类或接口相同,

  * 或者是参数 cls 表示的类或接口的父类,则返回 true。

  * 形象地:自身类.class.isAssignableFrom(自身类或子类.class) 返回 true

  * 例:

  * System.out.println(ArrayList.class.isAssignableFrom(Object.class));

   //false

  * System.out.println(Object.class.isAssignableFrom(ArrayList.class));

   //true

  */

if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) {

    return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);

 }

  Object retVal;

 //有时候目标对象内部的自我调用将无法实施切面中的增强则需要通过此属性暴露代理

  if (this.advised.exposeProxy) {

   oldProxy = AopContext.setCurrentProxy(proxy);

   setProxyContext = true;

 }

  target = targetSource.getTarget();

  if (target != null) {

   targetClass = target.getClass();

 }

 //获取当前方法的拦截器链

  List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice

  (method, targetClass);

  if (chain.isEmpty()) {

  //如果没有发现任何拦截器那么直接调用切点方法

   retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);

  }else {

  //将拦截器封装在 ReflectiveMethodInvocation,

  //以便于使用其 proceed 进行链接表用拦截器

  invocation = new ReflectiveMethodInvocation(proxy, target, method,

   args, targetClass, chain);

  //执行拦截器链

  retVal = invocation.proceed();

 }

  //返回结果

   if (retVal != null && retVal == target && method.getReturnType(). IsInstance

   (proxy) &&

    !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {

   retVal = proxy;

  }

   return retVal;

 }

  finally {

   if (target != null && !targetSource.isStatic()) {

    // Must have come from TargetSource.

   targetSource.releaseTarget(target);

  }

   if (setProxyContext) {

    // Restore old proxy.

   AopContext.setCurrentProxy(oldProxy);

  }

 }

}

上面的函数中最主要的工作就是创建了一个拦截器链,并使用 ReflectiveMethodInvocation 类进行了链的封装,而在 ReflectiveMethodInvocation 类的 proceed 方法中实现了拦截器的逐一调用,那么我们继续来探究,在 proceed 方法中是怎么实现前置增强在目标方法前调用后置增强在目标方法后调用的逻辑呢?

  if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.

public Object proceed() throws Throwable {

 // 执行完所有增强后执行切点方法

  size() - 1) {

   return invokeJoinpoint();

 }

 //获取下一个要执行的拦截器

 Object interceptorOrInterceptionAdvice =

  this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

  if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {

  //动态匹配,

   InterceptorAndDynamicMethodMatcher dm =

    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;

   if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {

    return dm.interceptor.invoke(this);

   }else {

   //不匹配则不执行拦截器

    return proceed();

  }

  }else {

  /*普通拦截器,直接调用拦截器,比如:

   * ExposeInvocationInterceptor、

   * DelegatePerTargetObjectIntroductionInterceptor、

   * MethodBeforeAdviceInterceptor

   * AspectJAroundAdvice、

   * AspectJAfterAdvice

   */

  //将 this 作为参数传递以保证当前实例中调用链的执行

   return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);

 }

}

在 proceed 方法中,或许代码逻辑并没有我们想象得那么复杂,ReflectiveMethodInvocation 中的主要职责是维护了链接调用的计数器,记录着当前调用链接的位置,以便链可以有序地进行下去,那么在这个方法中并没有我们之前设想的维护各种增强的顺序,而是将此工作委托给了各个增强器,使各个增强器在内部进行逻辑实现。

(2)CGLIB 使用示例。

CGLIB 是一个强大的高性能的代码生成包。它广泛地被许多 AOP 的框架使用,例如 Spring AOP 和 dynaop,为他们提供方法的 Interception(拦截)。最流行的 OR Mapping 工具 Hibernate 也使用 CGLIB 来代理单端 single-ended(多对一和一对一)关联(对集合的延迟抓取是采用其他机制实现的)。EasyMock 和 jMock 是通过使用模仿(moke)对象来测试 Java 代码的包。它们都通过使用 CGLIB 来为那些没有接口的类创建模仿(moke)对象。

CGLIB 包的底层通过使用一个小而快的字节码处理框架 ASM,来转换字节码并生成新的类。除了 CGLIB 包,脚本语言例如 Groovy 和 BeanShell,也是使用 ASM 来生成 Java 的字节码。当然不鼓励直接使用 ASM,因为它要求你必须对 JVM 内部结构包括 class 文件的格式和指令集都很熟悉。

我们先快速地了解 CGLIB 的使用示例。

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 EnhancerDemo {

  public static void main(String[] args) {

   Enhancer enhancer = new Enhancer();

  enhancer.setSuperclass(EnhancerDemo.class);

   enhancer.setCallback(new MethodInterceptorImpl());

   EnhancerDemo demo = (EnhancerDemo) enhancer.create();

  demo.test();

  System.out.println(demo);

 }

  public void test() {

   System.out.println("EnhancerDemo test()");

 }

  private static class MethodInterceptorImpl implements MethodInterceptor {

  @Override

   public Object intercept(Object obj, Method method, Object[] args,

   MethodProxy proxy) throws Throwable {

    System.err.println("Before invoke " + method);

    Object result = proxy.invokeSuper(obj, args);

    System.err.println("After invoke" + method);

    return result;

  }

 }

}

运行结果如下:

Before invoke public void EnhancerDemo.test()

EnhancerDemo test()

After invokepublic void EnhancerDemo.test()

Before invoke public java.lang.String java.lang.Object.toString()

Before invoke public native int java.lang.Object.hashCode()

After invokepublic native int java.lang.Object.hashCode()

After invokepublic java.lang.String java.lang.Object.toString()

EnhancerDemo$$EnhancerByCGLIB$$bc9b2066@1621e42

可以看到 System.out.println(demo), demo 首先调用了 toString() 方法,然后又调用了 hashCode,生成的对象为 EnhancerDemo$$EnhancerByCGLIB$$bc9b2066 的实例,这个类是运行时由 CGLIB 产生的。

完成 CGLIB 代理的类是委托给 Cglib2AopProxy 类去实现的,我们进入这个类一探究竟。

按照前面提供的示例,我们容易判断出来,Cglib2AopProxy 的入口应该是在 getProxy,也就是说在 Cglib2AopProxy 类的 getProxy 方法中实现了 Enhancer 的创建及接口封装。

public Object getProxy(ClassLoader classLoader) {

  if (logger.isDebugEnabled()) {

   logger.debug("Creating CGLIB2 proxy: target source is " + this.advised.

  getTargetSource());

 }

  try {

   Class rootClass = this.advised.getTargetClass();

   Assert.state(rootClass != null, "Target class must be available for creating

   a CGLIB proxy");

   Class proxySuperClass = rootClass;

   if (ClassUtils.isCglibProxyClass(rootClass)) {

    proxySuperClass = rootClass.getSuperclass();

    Class[] additionalInterfaces = rootClass.getInterfaces();

    for (Class additionalInterface : additionalInterfaces) {

    this.advised.addInterface(additionalInterface);

   }

  }

  //验证 Class

  validateClassIfNecessary(proxySuperClass);

  //创建及配置 Enhancer

   Enhancer enhancer = createEnhancer();

   if (classLoader != null) {

   enhancer.setClassLoader(classLoader);

    if (classLoader instanceof SmartClassLoader &&

    ((SmartClassLoader) classLoader).isClassReloadable(proxy

    SuperClass)) {

    enhancer.setUseCache(false);

   }

  }

  enhancer.setSuperclass(proxySuperClass);

   enhancer.setStrategy(new UndeclaredThrowableStrategy(UndeclaredThrowable

  Exception.class));

  enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));

  enhancer.setInterceptDuringConstruction(false);

  //设置拦截器

   Callback[] callbacks = getCallbacks(rootClass);

  enhancer.setCallbacks(callbacks);

   enhancer.setCallbackFilter(new ProxyCallbackFilter(

   this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap,

  this.fixedInterceptorOffset));

   Class[] types = new Class[callbacks.length];

   for (int x = 0; x < types.length; x++) {

    types[x] = callbacks[x].getClass();

  }

  enhancer.setCallbackTypes(types);

  //生成代理类以及创建代理

   Object proxy;

   if (this.constructorArgs != null) {

    proxy = enhancer.create(this.constructorArgTypes, this.constructorArgs);

  }

   else {

    proxy = enhancer.create();

  }

   return proxy;

 }

  catch (CodeGenerationException ex) {

   throw new AopConfigException("Could not generate CGLIB subclass of class [" +

   this.advised.getTargetClass() + "]: " +

   "Common causes of this problem include using a final class or a

   non-visible class",

  ex);

 }

  catch (IllegalArgumentException ex) {

   throw new AopConfigException("Could not generate CGLIB subclass of class [" +

   this.advised.getTargetClass() + "]: " +

   "Common causes of this problem include using a final class or a

   non-visible class",

  ex);

 }

  catch (Exception ex) {

   // TargetSource.getTarget() failed

   throw new AopConfigException("Unexpected AOP exception", ex);

 }

}

以上函数完整地阐述了一个创建 Spring 中的 Enhancer 的过程,读者可以参考 Enhancer 的文档查看每个步骤的含义,这里最重要的是通过 getCallbacks 方法设置拦截器链。

private Callback[] getCallbacks(Class rootClass) throws Exception {

 //对于 expose-proxy 属性的处理

  boolean exposeProxy = this.advised.isExposeProxy();

  boolean isFrozen = this.advised.isFrozen();

  boolean isStatic = this.advised.getTargetSource().isStatic();

 //将拦截器封装在 DynamicAdvisedInterceptor 中

  Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

  // Choose a "straight to target" interceptor. (used for calls that are

  // unadvised but can return this). May be required to expose the proxy.

  Callback targetInterceptor;

  if (exposeProxy) {

   targetInterceptor = isStatic ?

   new StaticUnadvisedExposedInterceptor (this.advised.getTargetSource().

   getTarget()) :

   new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());

  }else {

   targetInterceptor = isStatic ?

   new StaticUnadvisedInterceptor(this.advised.getTargetSource(). getTarget()) :

   new DynamicUnadvisedInterceptor(this.advised.getTargetSource());

 }

  // Choose a "direct to target" dispatcher (used for

  // unadvised calls to static targets that cannot return this).

  Callback targetDispatcher = isStatic ?

   new StaticDispatcher(this.advised.getTargetSource().getTarget()) :

   new SerializableNoOp();

  Callback[] mainCallbacks = new Callback[]{

  //将拦截器链加入 Callback 中

  aopInterceptor,

   targetInterceptor, // invoke target without considering advice, if optimized

   new SerializableNoOp(), // no override for methods mapped to this

   targetDispatcher, this.advisedDispatcher,

   new EqualsInterceptor(this.advised),

   new HashCodeInterceptor(this.advised)

 };

  Callback[] callbacks;

  // If the target is a static one and the advice chain is frozen,

  // then we can make some optimisations by sending the AOP calls

  // direct to the target using the fixed chain for that method.

  if (isStatic && isFrozen) {

   Method[] methods = rootClass.getMethods();

   Callback[] fixedCallbacks = new Callback[methods.length];

   this.fixedInterceptorMap = new HashMap<String, Integer>(methods.length);

   // TODO: small memory optimisation here (can skip creation for

   // methods with no advice)

   for (int x = 0; x < methods.length; x++) {

    List<Object> chain = this.advised.getInterceptorsAndDynamic Interception

    Advice(methods[x], rootClass);

    fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(

    chain, this.advised.getTargetSource().getTarget(), this.advised.

   getTargetClass());

    this.fixedInterceptorMap.put(methods[x].toString(), x);

  }

   // Now copy both the callbacks from mainCallbacks

   // and fixedCallbacks into the callbacks array.

   callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];

   System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);

   System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length,

  fixedCallbacks.length);

   this.fixedInterceptorOffset = mainCallbacks.length;

 }

  else {

   callbacks = mainCallbacks;

 }

  return callbacks;

}

在 getCallback 中 Spring 考虑了很多情况,但是对于我们来说,只需要理解最常用的就可以了,比如将 advised 属性封装在 DynamicAdvisedInterceptor 并加入在 callbacks 中,这么做的目的是什么呢,如何调用呢?在前面的示例中,我们了解到 CGLIB 中对于方法的拦截是通过将自定义的拦截器(实现 MethodInterceptor 接口)加入 Callback 中并在调用代理时直接激活拦截器中的 intercept 方法来实现的,那么在 getCallback 中正是实现了这样一个目的,Dynamic AdvisedInterceptor 继承自 MethodInterceptor,加入 Callback 中后,在再次调用代理时会直接调用 DynamicAdvisedInterceptor 中的 intercept 方法,由此推断,对于 CGLIB 方式实现的代理,其核心逻辑必然在 DynamicAdvisedInterceptor 中的 intercept 中。

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy)

throws Throwable {

  Object oldProxy = null;

  boolean setProxyContext = false;

  Class targetClass = null;

  Object target = null;

  try {

   if (this.advised.exposeProxy) {

    // Make invocation available if necessary.

    oldProxy = AopContext.setCurrentProxy(proxy);

    setProxyContext = true;

  }

   target = getTarget();

   if (target != null) {

    targetClass = target.getClass();

  }

  //获取拦截器链

   List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice

  (method, targetClass);

   Object retVal;

   if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {

   //如果拦截器链为空则直接激活原方法

    retVal = methodProxy.invoke(target, args);

   }else {

   //进入链

    retVal = new CglibMethodInvocation(proxy, target, method, args,

    targetClass, chain, methodProxy).proceed();

  }

   retVal = massageReturnTypeIfNecessary(proxy, target, method, retVal);

   return retVal;

 }

  finally {

   if (target != null) {

   releaseTarget(target);

  }

   if (setProxyContext) {

    // Restore old proxy.

   AopContext.setCurrentProxy(oldProxy);

  }

 }

}

上述的实现与 JDK 方式实现代理中的 invoke 方法大同小异,都是首先构造链,然后封装此链进行串联调用,稍有些区别就是在 JDK 中直接构造 ReflectiveMethodInvocation,而在 cglib 中使用 CglibMethodInvocation。CglibMethodInvocation 继承自 ReflectiveMethodInvocation,但是 proceed 方法并没有重写。

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。