揭秘Spring(三)_Spring之AOP

引:前一节讲到Spring的核心概念IOC,那么就不能不提到Spring的另一个核心概念AOP,我们先是先讲一下它的概念与原理实现,然后在讲Spring中AOP的实现。

AOP

AOP思想

AOP(Aspect Oriented Programming的缩写,意为:面向切面编程)是对OOP的一种补充。

  • 面向对象(OOP)引入了继承、多态、封装,将系统的业务功能按照模块划分,每个模块用一个或多个类来表示。而对于一些系统功能,无法使用OOP的思想来实现它们。这些系统功能往往穿插在业务功能的各处,和业务代码耦合在一起;而且系统功能往往会被重复使用,这就导致了模块不利于复用,这就是使用OOP实现系统功能的弊端。
  • AOP即为面向切面编程,它把系统需求按照功能分门归类,把它们封装在一个个切面中,然后再指定这些系统功能往业务功能,主要应用于权限认证、日志,事务等。

它的主要是好处如下:

  • 降低模块之间的耦合度

  • 使系统容易扩展

  • 更好的代码复用。

AOP实现原理

实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。而Spring采用的是动态代理技术,关于动态代理的实现可以参照自己之前的博客 设计模式之禅——代理模式一文中的动态代理这一节去了解。

SpringAOP实现

Spring的AOP实现遵守AOP联盟的约定。同时Spring又扩展了它,增加了Pointcut、Advisor等一些接口使得其更加灵活。

Spring AOP的基本概念

  • 切面(Aspect):类似于OOP中的Class,一个Aspect存放一个系统功能的所有逻辑。切面用Spring的 Advisor或拦截器实现。
  • 连接点(Joinpoint):程序执行过程中的某一事件,如方法被调用时、抛出异常时。
  • 切入点(Pointcut):指定一个通知将被引发的一系列连接点的集合。AOP框架必须允许开发者指定切入点:例如,使用正则表达式。 Spring定义了Pointcut接口,用来组合MethodMatcher和ClassFilter,可以通过名字很清楚的理解, MethodMatcher是用来检查目标类的方法是否可以被应用此通知,而ClassFilter是用来检查Pointcut是否应该应用到目标类上。
  • 引入(Introduction): 添加方法或字段到被通知的类。 Spring允许引入新的接口到任何被通知的对象。例如,你可以使用一个引入使任何对象实现 IsModified接口,来简化缓存。Spring中要使用Introduction, 可有通过DelegatingIntroductionInterceptor来实现通知,通过DefaultIntroductionAdvisor来配置Advice和代理类要实现的接口。
  • 目标对象(Target Object): 包含连接点的对象。也被称作被通知或被代理对象(POJO)。
  • AOP代理(AOP Proxy): AOP框架创建的对象,包含通知。 在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。
  • 织入(Weaving): 组装方面来创建一个被通知对象。这可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。
  • 通知(Advice):具体的横切逻辑;Spring中有五种Advice:
    • 前置通知(Before Advice)
    • 后置通知(After Advice)
    • 返回通知(After Return Advice)
    • 环绕通知(Around Advice)
    • 抛出异常后通知(After Throwing Advice)

SpringAOP动态代理

Spring AOP中使用了两种动态代理,一种是JDK的动态代理,一种CGLIB的动态代理。JDK的动态代理必须指定接口,这些接口都是已经被代理对象实现了的;而CGLIB代理则不需要指定接口。

JDK动态代理

如果被代理对象实现了需要被代理的接口,则使用JDK的动态代理。我们一步步来看这个过程:

  1. 首先明确我们使要生成一个代理,而Spring的内部机制是由FactoryBean的getObject方法来产生的,所以我们会一步步debug到这个方法行(在FactoryBeanRegistrySupport类的doGetObjectFromFactoryBean中),我们看看这个方法的源代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public Object getObject() throws BeansException {
    // 初始化通知器链,为代理对象配置通知器链。
    this.initializeAdvisorChain();
    //区分SingleTon和ProtoType,生成对应的Proxy
    if(this.isSingleton()) {
    // 只有SingleTon的Bean才会一开始就初始化,ProtoType的只有在请求的时候才会初始化,代理也一样
    return this.getSingletonInstance();
    } else {
    if(this.targetName == null) {
    this.logger.warn("Using non-singleton proxies with singleton targets is often undesirable. Enable prototype proxies by setting the 'targetName' property.");
    }

    return this.newPrototypeInstance();
    }
    }
  2. 到达getObject方法后,我们需要去看看它是怎么初始化通知链的就是initializeAdvisorChain的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
     private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
    // 初始化过程的标志位advisorChainInitialized,这个标志用来表示通知器链是否已经初始化。
    if(!this.advisorChainInitialized) {
    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));
    }

    if(this.interceptorNames[this.interceptorNames.length - 1].endsWith("*") && this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
    throw new AopConfigException("Target required after globals");
    }

    String[] var1 = this.interceptorNames;
    int var2 = var1.length;

    for(int var3 = 0; var3 < var2; ++var3) {
    String name = var1[var3];
    if(this.logger.isTraceEnabled()) {
    this.logger.trace("Configuring advisor or advice '" + name + "'");
    }

    if(name.endsWith("*")) {
    if(!(this.beanFactory instanceof ListableBeanFactory)) {
    throw new AopConfigException("Can only use global advisors or interceptors with a ListableBeanFactory");
    }

    this.addGlobalAdvisor((ListableBeanFactory)this.beanFactory, name.substring(0, name.length() - "*".length()));
    } else {
    Object advice;
    if(!this.singleton && !this.beanFactory.isSingleton(name)) {
    advice = new ProxyFactoryBean.PrototypePlaceholderAdvisor(name);
    } else {
    advice = this.beanFactory.getBean(name);
    }

    this.addAdvisorOnChainCreation(advice, name);
    }
    }
    }

    this.advisorChainInitialized = true;
    }
    }

    初始化只是在应用第一次通过ProxyFactoryBean获取代理对象的时候。完成这个初始化之后,接着会读取配置中出现的所有通知器(把通知器的名字交给容器的getBean,IOC容器的回调获取通知器),把通知器加入拦截器链(addAdvisoronChainCreation实现)。

  3. 生成代理对象,利用ProxyFactoryBean的getSingletonInstance方法,源码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     private synchronized Object getSingletonInstance() {
    if(this.singletonInstance == null) {
    //这里会调用getBean,获取被代理对象
    this.targetSource = this.freshTargetSource();
    if(this.autodetectInterfaces && this.getProxiedInterfaces().length == 0 && !this.isProxyTargetClass()) {
    // 根据 AOP 框架判断需要代理的接口
    Class<?> targetClass = this.getTargetClass();
    if(targetClass == null) {
    throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
    }
    //这里是设置代理对象的接口
    this.setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
    }

    super.setFrozen(this.freezeProxy);
    //这里方法会使用ProxyFactory生成需要的Proxy
    this.singletonInstance = this.getProxy(this.createAopProxy());
    }

    return this.singletonInstance;
    }
  4. 进入ProxyCreatorSupport的createAopProxy,源码如下:

    1
    2
    3
    4
    5
    6
    7
     protected final synchronized AopProxy createAopProxy() {
    if (!this.active) {
    activate();
    }
    //通过AopProxyFactory取得AopProxy,AopProxyFactory是在初始化函数中定义的,使用的是DefaultAopProxyFactory
    return getAopProxyFactory().createAopProxy(this);
    }
  5. 那么DefaultAopProxyFactory如何生成AopProxy了,这里有两种方式,JdkDynamicAopProxy和CglibProxyFactory,DefaultAopProxyFactory的createAopProxy的源码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
    @Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
    //获取配置的目标对象
    Class<?> targetClass = config.getTargetClass();
    if (targetClass == null) {
    //如果没有目标对象,抛出异常,提醒AOP应用提供正确的目标配置
    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是一个第三方类库,所以需要在CLASSPATH中配置
    return new ObjenesisCglibAopProxy(config);
    }
    else {
    return new JdkDynamicAopProxy(config);
    }
    }
    }
  6. 由于我们这里目标类是接口,所以采用JdkDynamicAopProxy 生成AopProxy代理对象,我们可以看一下JdkDynamicAopProxy的invoke方法源码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Object oldProxy = null;
    boolean setProxyContext = false;
    TargetSource targetSource = this.advised.targetSource;
    Class<?> targetClass = null;
    Object target = null;

    Object var13;
    try {
    if(!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
    Boolean var20 = Boolean.valueOf(this.equals(args[0]));
    return var20;
    }
    if(!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
    Integer var18 = Integer.valueOf(this.hashCode());
    return var18;
    }

    if(method.getDeclaringClass() == DecoratingProxy.class) {
    Class var17 = AopProxyUtils.ultimateTargetClass(this.advised);
    return var17;
    }

    Object retVal;

    // Advised接口或者其父接口中定义的方法,直接反射调用,不应用通知
    if(!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) {
    retVal = AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
    return 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);
    // 如果没有可以应用到此方法的通知(Interceptor),此直接反射调用 method.invoke(target, args)
    if(chain.isEmpty()) {
    Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
    retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
    } else {
    //创建MethodInvocation
    MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
    // 处理通知
    retVal = invocation.proceed();
    }

    Class<?> returnType = method.getReturnType();
    if(retVal != null && retVal == target && returnType != Object.class && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
    retVal = proxy;
    } else if(retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
    throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);
    }

    var13 = retVal;
    } finally {
    if(target != null && !targetSource.isStatic()) {
    targetSource.releaseTarget(target);
    }

    if(setProxyContext) {
    AopContext.setCurrentProxy(oldProxy);
    }

    }

    return var13;
    }

CGLIB动态代理

如果被代理对象没有实现需要被代理的接口,则使用CGLIB动态代理,CGLIB动态代理按照前面的分析基本与JDK动态代理一样,由于在Spring AOP中对应的包装类为CglibAopProxy,CglibAopProxy的intercept回调方法的实现和JdkDynamicAopProxy的回调实现是非常类似的,只是在CglibAopProxy中构造的是CglibMethodInvocation对象来完成拦截器链的调用,这里看一下与invoke类似的getCallbacks源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
boolean exposeProxy = this.advised.isExposeProxy();
boolean isFrozen = this.advised.isFrozen();
boolean isStatic = this.advised.getTargetSource().isStatic();
Callback aopInterceptor = new CglibAopProxy.DynamicAdvisedInterceptor(this.advised);
Object targetInterceptor;
if(exposeProxy) {
targetInterceptor = isStatic?new CglibAopProxy.StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()):new CglibAopProxy.DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());
} else {
targetInterceptor = isStatic?new CglibAopProxy.StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()):new CglibAopProxy.DynamicUnadvisedInterceptor(this.advised.getTargetSource());
}

Callback targetDispatcher = (Callback)(isStatic?new CglibAopProxy.StaticDispatcher(this.advised.getTargetSource().getTarget()):new CglibAopProxy.SerializableNoOp());
Callback[] mainCallbacks = new Callback[]{aopInterceptor, (Callback)targetInterceptor, new CglibAopProxy.SerializableNoOp(), targetDispatcher, this.advisedDispatcher, new CglibAopProxy.EqualsInterceptor(this.advised), new CglibAopProxy.HashCodeInterceptor(this.advised)};
Callback[] callbacks;
if(isStatic && isFrozen) {
Method[] methods = rootClass.getMethods();
Callback[] fixedCallbacks = new Callback[methods.length];
this.fixedInterceptorMap = new HashMap(methods.length);

for(int x = 0; x < methods.length; ++x) {
// 获得拦截链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);
// 准备处理通知
fixedCallbacks[x] = new CglibAopProxy.FixedChainStaticTargetInterceptor(chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
this.fixedInterceptorMap.put(methods[x].toString(), Integer.valueOf(x));
}

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;
}

参考

  1. 深入剖析Spring(四)——AOP
  2. Spring AOP源码分析(生成代理对象)
  3. Spring AOP四种实现方式Demo详解与相关知识探究