spring aop

要讲spring的aop,就不能不讲代理。

核心类图

动态代理类图

动态代理

spring Aop使用jdk动态代理或者cglib代理来为实例创建代理。(AopProxy接口的两个实现类分别是JdkDynamicAopProxyCglibAopProxy)

如果目标对象实现了至少一个接口,那么jdk动态代理将会被使用。所有被这个目标类实现的接口都将被代理。如果目标对象没有实现任何的接口,那么cglib代理将被创建。

如果你想强制使用cglib代理(例如,想代理目标对象中所有的方法,而不仅仅是实现的接口的方法),你可以做这些,但是有一些问题需要考虑:

final 方法不能被advised,因为他们不能被重写 从3.20版本,cglib被包含org.srpingframework的spring-croe jar包中 为了强制使用cglib代理,将中proxy-target-class设为true

<aop:config proxy-target-class="true">
    <!-- other beans defined here... -->
</aop:config>

在使用@Aspectj自动代理时,为了强制使用cglib,需要设置的属性`proxy-target-class`为true。

<aop:aspectj-autoproxy proxy-target-class="true"/>

使用proxy-target-class=true 在<tx:annotation-driven/>,<aop:aspectj-autoproxy/>,<aop:config/>任一,会使cglib代理在三者都生效。

静态代理

aspectj

aop

aop术语

Advice(通知)

action taken by an aspect at a particular join point. Different types of advice include “around,” “before” and “after” advice. (Advice types are discussed below.) Many AOP frameworks, including Spring, model an advice as an interceptor, maintaining a chain of interceptors around the join point.

定义在连接点做什么,为切面增强提供织入接口,在spring aop中,它主要描述spring aop围绕方法调用而注入的切面行为。

各advice类图 advice

JoinPoint(连接点)

a point during the execution of a program, such as the execution of a method or the handling of an exception. In Spring AOP, a join point always represents a method execution。

PointCut(切点)

a predicate that matches join points. Advice is associated with a pointcut expression and runs at any join point matched by the pointcut (for example, the execution of a method with a certain name). The concept of join points as matched by pointcut expressions is central to AOP, and Spring uses the AspectJ pointcut expression language by default.

pointcut决定advice应该作用于哪个joinPoint,也就是说通过pointcut来定义需要增强的方法的集合,这些集合的选取可以按照一定的规则来完成。

Aspect/Advisor(切面/通知器)

a modularization of a concern that cuts across multiple classes. Transaction management is a good example of a crosscutting concern in enterprise Java applications. In Spring AOP, aspects are implemented using regular classes (the schema-based approach) or regular classes annotated with the @Aspect annotation (the @AspectJ style).切面是

advisor通知器 完成对目标方法的切面增强设计(Advice)和关注点的设计(Pointcut)以后,需要一个对象把它们结合起来,完成这个作用的就是Advisor(通知器)

ps: aspect和advisor的区别aspect和advisor

  1. Adivisor是一种特殊的Aspect,Advisor代表spring中的Aspect
  2. 区别:advisor只持有一个Pointcut和一个advice,而aspect可以多个pointcut和多个advice

It is perfectly possible to mix @AspectJ style aspects using the autoproxying support, schema-defined aspects, declared advisors and even proxies and interceptors defined using the Spring 1.2 style in the same configuration. All of these are implemented using the same underlying support mechanism and will co-exist without any difficulty. [官方文档](https://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html#aop-mixing-styles)

Introduction

declaring additional methods or fields on behalf of a type. Spring AOP allows you to introduce new interfaces (and a corresponding implementation) to any advised object. For example, you could use an introduction to make a bean implement an IsModified interface, to simplify caching. (An introduction is known as an inter-type declaration in the AspectJ community.)

Weaving

linking aspects with other application types or objects to create an advised object. This can be done at compile time (using the AspectJ compiler, for example), load time, or at runtime. Spring AOP, like other pure Java AOP frameworks, performs weaving at runtime. 织入是把切面应用到目标对象并创建新的代理对象的过程。切面在指定的连接点织入到目标对象。在目标对象的生命周期里有多个点可以进行织入: * 编译期:切面在目标类编译时被织入,这种方式需要特殊的编译器,Aspectj的织入编译器就是以这种方法织入切面的 * 类加载期: 切面在目标类加载到jvm时被织入。这种方式需要特殊的类加载器,它可以在目标类在被引入应用之前增强该目标类的字节码,Aspectj5的加载时织入(load-time weaving,LTW)就支持以这种方式织入切面 * 运行时: 切面在应用运行的某个时刻被织入,一般情况下,在织入切面时,aop容器会为目标对象动态创建一个代理对象。spring aop就是以这种方式织入切面的。

以实战中例子说明如下:

aop例子说明

切点表达式

正如前面所述,切点用于准确定位应该在什么地方应用切面的通知。通知和切点是切面的最基本元素。因此了解如何编写切点非常重要。

在spring aop中,要使用aspectj的切点表达式语言来定义切点,spring aop仅支持aspectj切点指示器的一个子集。

aspectj指示器 描述 示例
arg() 限制连接点匹配参数为指定类型的执行方法  
@arg() 限制连接点匹配参数由指定注解标注的执行方法  
execution() 用于匹配是连接点的执行方法  
this() 限制连接点匹配aop代理的bean引用为指定类型的类  
target() 限制连接点匹配目标对象为指定类型的类  
@target() 限制连接点匹配特定的执行对象,这些对象对应的类要具有指定类型的注解  
within() 限制连接点匹配指定的类型  
@within() 限制连接点匹配指定注解所标注的类型(当使用spring aop时,方法定义在由指定注解所标注的类里)  
@annotation() 限制匹配带有指定注解的连接点  

ps:

  1. 在spring中尝试使用aspectj其他指示器时,将会抛出IIlegalArgument Exception异常。
  2. 只有execution指示器是实际执行匹配的,而其他的指示器都是用来限制匹配的。

((AnnotationInvocationHandler)((Proxy)((JoinPointMatchImpl)pmi.getUserAttribute(“@annotation(lifecycle)”)).getParameterBindings()[0].getBinding()).h).memberValues.get(“name”)

举例如下: aspectj_expression

spring aop通知顺序

《Spring设计思想》AOP实现原理(基于JDK和基于CGLIB)

Aop设计基本原理

Spring AOP源码(十四) 分析ProxyFactoryBean

spring aop