前言

Github:https://github.com/yihonglei/thinking-in-spring

关于AOP概念和AOP的实战:

Spring使用注解 AOP实战

Spring使用XML AOP实战

本篇是以ProxyFactoryBean的配置来讲的,这个是最能体现AOP思想的一个配置方式,也是我们学习AOP一个入口。

一 设计原理

    在Spring的AOP模块中,一个主要的部分就是AopProxy代理对象的生成,而对于Spring应用,可以看到,是通过配置

和调用Spring的ProxyFactoryBean来完成这个任务的。在ProxyFactoryBean中,封装了主要代理对象的生成过程。

在这个生成过程中,可以使用JDK的Proxy和CGLIB两种方式。

关于代理模式和JDK、CGLIB动态代理参考:

代理模式

JDK动态代理实现原理

CGLIB动态代理实现原理

以ProxyFactory的设计为中心,看下整个继承关系图:

在这个类继承关系图中,可以看到完成AOP应用的类,类说明:

ProxyConfig:

    作为共同基类,可以看成是一个数据基类,这个数据基类为ProxyFactoryBean这样的子类提供了配置属性。

AdvisedSupport:

    封装了AOP对通知和通知器的相关操作,这些操作对于不同的AOP的代理对象的生成都是一样的,但对于

具体的AOP代理对象的创建,AdvisedSupport把它交给它的子类们去完成。

ProxyCreatorSupport:

    是其子类创建AOP代理对象的一个辅助类。

AspectJProxyFactory:

    集成Spring和AspectJ的作用,适用于需要使用AspectJ的AOP应用。

ProxyFactoryBean:

    Spring的AOP应用,可以在IOC中声明式配置。

ProxyFactory:

    Spring的AOP应用,需要编程式使用。

二 配置ProxyFactoryBean

    在分析Spring AOP的实现原理中,主要以ProxyFactoryBean的实现作为例子和实现的基本线索进行分析。这是因为

ProxyFactoryBean是在Spring IOC环境中创建AOP最底层的方法,也是最灵活的方法,Spring通过它完成了对AOP使用

的封装。以ProxyFactoryBean为实现入口,逐层深入,是快速理解Spring AOP实现的学习路径。

    在了解ProxyFactoryBean的实现之前,先了解ProxyFactoryBean的配置和使用,在基于XML配置Spring的Bean时

需要经历以下几个步骤:

1)定义使用的通知器Advisor,这个通知器应该作为一个Bean来定义。这个通知器实现了对目标对象进行增强的

切面行为,也就是Advice通知;

2)定义ProxyFactoryBean:interceptorNames是指定义的通知器,可以有多个;

3)定义target属性,需要增强的类,从源码上看只能有一个;

Spring XML关于ProxyFactoryBean使用配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 业务Bean -->
    <bean name="conferenceService" class="com.jpeony.spring.ConferenceServiceImpl"></bean>

    <!--配置Advice-->
    <bean name="logAdvice" class="com.jpeony.spring.aop.LoggerAdvice"></bean>

    <!--配置ProxyFactoryBean-->
    <bean name="aopMethod" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!-- 指定通知器 -->
        <property name="interceptorNames">
            <list>
                <value>logAdvice</value>
            </list>
        </property>
        <!-- 需要增强的类 -->
        <property name="target" ref="conferenceService"/>
    </bean>

</beans>

定义通知器Advisor:

package com.jpeony.spring.aop;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;

public class LoggerAdvice implements MethodBeforeAdvice{

    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("系统日志:"+(new Date())+":"+"调用了"+method.getName()+" :使用了参数"+(Arrays.toString(args)));
    }
}

定义Target:

package com.jpeony.spring;

public interface ConferenceService {
    void conference();
}
package com.jpeony.spring;

public class ConferenceServiceImpl implements ConferenceService {

    @Override
    public void conference() {
        System.out.println("开会......");
    }

}

测试类:

package com.jpeony.spring;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestAop {

    @Test
    public void testAop() {
        // 根据配置文件创建IOC容器
        ApplicationContext context =
                new ClassPathXmlApplicationContext("applicationContext-aop.xml");
        // 从容器中获取Bean
        ConferenceService conferenceService = (ConferenceService) context.getBean("aopMethod");
        // 调用Bean方法
        conferenceService.conference();
    }

}

结果:

从打印结果,可以看到,成功对目标类实现了增强功能。

下面接着看ProxyFactoryBean是如何对Target对象起作用的,为何如此配置就能实现增强的效果。

三 ProxyFactoryBean生成AopProxy代理对象

    在Spring AOP的使用中,我们已经了解到,可以通过ProxyFactoryBean来配置目标对象和切面行为。

这个ProxyFactoryBean是一个FactoryBean,关于FactoryBean和BeanFactory说明参考:

FactoryBean和BeanFactory区别

    在ProxyFactoryBean中,通过interceptorNames属性来配置已经定义好的通知器Advisor。

虽然名字叫interceptorNames,但实际上是提供AOP应用配置通知的地方。在ProxyFactoryBean中需要为

target目标对象生成Proxy代理对象,从而为AOP横切面的编织做好准备工作。 

 

AopProxy代理对象的生成过程:

 

    从FactoryBean中获取对象,以getObject()方法作为入口完成的,ProxyFactoryBean需要实现FactoryBean中的

getObject()方法。对于ProxyFactoryBean来说,把需要对target目标对象增加的增强处理,都通过getObject()方法

进行封装,这些增强处理是为AOP功能实现提供服务的。

    getObject()首先对通知链进行初始化,通知器链封装了一序列的拦截器,这些拦截器都要从序列中读取,然后为

代理对象的生成做好准备。在生成代理对象时,因为Spring中有singleton类型和prototype类型这两种不同的bean,

所以要对代理对象的生成做一个区分。ProxyFactoryBean的AOP实现需要依赖JDK或者CGLIB提供的Proxy特性。

ProxyFactoryBean的类图:

ProxyFactoryBean.getObject()方法源码:

@Override
public Object getObject() throws BeansException {
   // 通知器链进行初始化,通知器链封装了一序列的拦截器,这些拦截器都要从序列中读取,
   // 然后为代理对象的生成做好准备。
   initializeAdvisorChain();
   // 判断是singleton还是prototype属性,选择不同的AopProxy创建实现
   if (isSingleton()) {
      return getSingletonInstance();
   }
   else {
      if (this.targetName == null) {
         logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
               "Enable prototype proxies by setting the 'targetName' property.");
      }
      return newPrototypeInstance();
   }
}

ProxyFactoryBean.initializeAdvisorChain()方法源码:

private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
   if (this.advisorChainInitialized) {
      return;
   }

   if (!ObjectUtils.isEmpty(this.interceptorNames)) {
      if (this.beanFactory == null) {
         throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
               "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
      }

      // Globals can't be last unless we specified a targetSource using the property...
      if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
            this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
         throw new AopConfigException("Target required after globals");
      }

      // Materialize interceptor chain from bean names.
      // 这里添加Advisor链的调用,通过interceptorNames属性进行配置
      for (String name : this.interceptorNames) {
         if (logger.isTraceEnabled()) {
            logger.trace("Configuring advisor or advice '" + name + "'");
         }

         if (name.endsWith(GLOBAL_SUFFIX)) {
            if (!(this.beanFactory instanceof ListableBeanFactory)) {
               throw new AopConfigException(
                     "Can only use global advisors or interceptors with a ListableBeanFactory");
            }
            addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
                  name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
         }

         else {
            // If we get here, we need to add a named interceptor.
            // We must check if it's a singleton or prototype.
            // 如果程序在这里被调用,那么需要加入命名的拦截器Advice,并且需要检查Bean是singleton还是prototype类型。
            Object advice;
            // singleton类型处理
            if (this.singleton || this.beanFactory.isSingleton(name)) {
               // Add the real Advisor/Advice to the chain.
               advice = this.beanFactory.getBean(name);
            }
            else {
               // It's a prototype Advice or Advisor: replace with a prototype.
               // Avoid unnecessary creation of prototype bean just for advisor chain initialization.
              // prototype类型处理
               advice = new PrototypePlaceholderAdvisor(name);
            }
            addAdvisorOnChainCreation(advice, name);
         }
      }
   }

   this.advisorChainInitialized = true;
}

initializeAdvisorChain()方法为Proxy代理对象配置Advisor链。通过advisorChainInitialized来判断通知器链是否初始化。

如果已经初始化,就无需再初始化,直接返回;完成初始化之后,把从IOC容器中取得的通知器加入拦截器链中,

这个动作由addAdvisorOnChainCreation完成。

接下来看ProxyFactoryBean.getSingletonInstance()方法源码:

private synchronized Object getSingletonInstance() {
   if (this.singletonInstance == null) {
      this.targetSource = freshTargetSource();
      if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
         // Rely on AOP infrastructure to tell us what interfaces to proxy.
         // 根据AOP框架来判断需要代理的接口
         Class<?> targetClass = getTargetClass();
         if (targetClass == null) {
            throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
         }
         // 设置代理对象的接口
         setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
      }
      // Initialize the shared singleton instance.
      super.setFrozen(this.freezeProxy);
      // 使用相应的动态代理技术生产AopProxy代理对象
      this.singletonInstance = getProxy(createAopProxy());
   }
   return this.singletonInstance;
}

getSingletonInstance()这个方法是ProxyFactoryBean生成AopProxy代理对象的调用入口。代理对象会封装对target目标

对象的调用,也即是通过createAopProxy()返回代理对象。

代理对象生成ProxyCreatorSupport.createAopProxy()方法源码:

protected final synchronized AopProxy createAopProxy() {
   if (!this.active) {
      activate();
   }
   // 通过AopProxyFactory取得AopProxy,这个AopProxyFactory是在初始函数中定义的,使用DefaultAopProxyFactory。
   return getAopProxyFactory().createAopProxy(this);
}

具体对象生成在接口AopProxyFactory中的createAopProxy(),方法签名:

AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException;

createAopProxy方法的具体实现在DefaultAopProxyFactory中实现。

DefaultAopProxyFactory.createAopProxy()方法源码:

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
   if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
      Class<?> targetClass = config.getTargetClass();
      // 如果targetClass是接口类,使用JDK来生成Proxy
      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() || Proxy.isProxyClass(targetClass)) {
         return new JdkDynamicAopProxy(config);
      }
      // 如果不是接口类,使用CGLIB生成Proxy
      return new ObjenesisCglibAopProxy(config);
   }
   else {
      return new JdkDynamicAopProxy(config);
   }
}

  该方法在AopProxy生成过程中,首先需要从AdvisedSupport对象中取得配置的目标对象,然后根据目标对象类型,

选择不同的代理对象生成方式。

    关于AopProxy代理对象的生成,需要考虑使用哪种方式生成,如果目标对象是接口类,适合用JDK动态代理生成,

否则,适合用CGLIB动态代理生成。

四 JDK生成AopProxy代理对象

    上面说过,AopProxy代理对象可以由JDK或CGLIB来生成,而JdkDynamicAopProxy和CglibAopProxy实现

都继承了AopProxy接口。

AopProxy继承关系图:

这里主要讨论JdkDynamicAopProxy如何生成AopProxy代理对象的。

先回顾一下ProxyFactoryBean.getSingletonInstance()方法源码:

private synchronized Object getSingletonInstance() {
   if (this.singletonInstance == null) {
      this.targetSource = freshTargetSource();
      if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
         // Rely on AOP infrastructure to tell us what interfaces to proxy.
         Class<?> targetClass = getTargetClass();
         if (targetClass == null) {
            throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
         }
         setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
      }
      // Initialize the shared singleton instance.
      super.setFrozen(this.freezeProxy);
      this.singletonInstance = getProxy(createAopProxy());
   }
   return this.singletonInstance;
}

在该法中有一个createAopProxy(),该方法具体实现在DefaultAopProxyFactory中。

DefaultAopProxyFactory.createAopProxy()方法源码:

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
   if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
      Class<?> targetClass = config.getTargetClass();
      // 如果targetClass是接口类,使用JDK来生成Proxy
      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() || Proxy.isProxyClass(targetClass)) {
         return new JdkDynamicAopProxy(config);
      }
      // 如果不是接口类,使用CGLIB生成Proxy
      return new ObjenesisCglibAopProxy(config);
   }
   else {
      return new JdkDynamicAopProxy(config);
   }
}

该方法会返回一个JdkDynamicAopProxy或者CglibAopProxy对象,返回的对象会传入getProxy()方法中。

this.singletonInstance = getProxy(createAopProxy());

真正生成我们想要的AopProxy代理对象在getProxy()方法中完成。

ProxyFactoryBean.getProxy()方法源码:

protected Object getProxy(AopProxy aopProxy) {
   return aopProxy.getProxy(this.proxyClassLoader);
}

getProxy()方法为AopProxy的一个接口方法,签名如下:

Object getProxy(ClassLoader classLoader);

上面说过,JdkDynamicAopProxy和CglibAopProxy为具体实现,这里讨论jdk,所以看下JdkDynamicAopProxy

中的实现。

JdkDynamicAopProxy.getProxy()源码:

@Override
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, true);
   findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
   // 调用jdk生成proxy的地方
   return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

生成代理对象时,需要指明三个参数,类加载器,代理接口,Proxy回调方法所在的对象。

五 CGLIB生成AopProxy代理对象

关于CGLIB生成代理对象直接看CglibAopProxy关于getProxy()方法的实现,前面流程与jdk生产代理对象一样。

CglibAopProxy.getProxy()源码:

@Override
public Object getProxy(ClassLoader classLoader) {
   if (logger.isDebugEnabled()) {
      logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
   }
   // 从advised中取得在IOC容器中配置的target对象
   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);
         }
      }

      // Validate the class, writing log messages as necessary.
      // 验证代理对象的接口设置
      validateClassIfNecessary(proxySuperClass, classLoader);

      // Configure CGLIB Enhancer...
      // 创建并配置Cglib的Enhancer,这个Enhancer对象是Cglib的主要操作类
      Enhancer enhancer = createEnhancer();
      if (classLoader != null) {
         enhancer.setClassLoader(classLoader);
         if (classLoader instanceof SmartClassLoader &&
               ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
            enhancer.setUseCache(false);
         }
      }
      // 设置Enhancer对象,包括设置代理接口,回调方法
      // 来自advised的IOC容器配置
      enhancer.setSuperclass(proxySuperClass);
      enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
      enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
      enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

      Callback[] callbacks = getCallbacks(rootClass);
      Class<?>[] types = new Class<?>[callbacks.length];
      for (int x = 0; x < types.length; x++) {
         types[x] = callbacks[x].getClass();
      }
      // fixedInterceptorMap only populated at this point, after getCallbacks call above
      enhancer.setCallbackFilter(new ProxyCallbackFilter(
            this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
      enhancer.setCallbackTypes(types);

      // Generate the proxy class and create a proxy instance.
      // 创建AopProxy代理对象
      return createProxyClassAndInstance(enhancer, callbacks);
   }
   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 (Throwable ex) {
      // TargetSource.getTarget() failed
      throw new AopConfigException("Unexpected AOP exception", ex);
   }
}

    到这里,我们生产了代理对象,通过使用AopProxy对象封装target目标对象之后,

ProxyFactoryBean的getObject()方法得到的对象就不是一个普通的Java对象了,而是一个AopProxy的代理对象。

这个时候已经不会让应用直接调用target的方法实现了,而是先被AopProxy代理对象拦截,对于不同的AopProxy

代理对象的不同生成方法,拦截入口不同。比如:JDK使用的是InvocationHandler使用的是invoke入口,

而Cglib使用的是设置好的callback回调。

    可以把AOP的实现部分看成是由基础设施准备和AOP运行辅助两个部分组成,这里讨论的AopProxy代理对象的生成,

可以看成是一个静态的AOP基础设施的建立过程。通过这个准备过程,把代理对象、拦截器(通知器)这些待调用的部分

都准备好,等待着AOP运行过程中对这些基础设施的使用。

    对于应用触发的AOP应用,会涉及AOP框架的运行和对AOP基础设施的使用。这些动态的运行部分,是从前面提到

的拦截器的回调入口开始的,这些拦截器调用的实现原理,和AopProxy代理对象生成一样,也是AOP实现的重要组成

部分,下篇文章重点分析Spring AOP拦截器调用的实现原理。

参考文献

1、《Spring技术内幕》

2、《Spring实战》

3、Spring官网API

4、Spring源码

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐