Spring AOP:Aspect-oriented Programming,即面向切面编程。在切面编程中,引入了一些新的概念,这在学习AOP之前,必须得弄清楚,且得明白它们之前的关联关系,否则在后面的源码学习中会比较绕。毕竟,弄清楚了他们各自的功能,我们就能很容易的带着问题逐个击破,接下来我逐个讲解。
Aspect
翻译过来,叫做切面。首先看一下Spring广官方是如何给出解释的。切面是跨越多个类的关注的模块化。事务管理是企业Java应用程序中横切关注点的一个很好的例子。在Spring AOP中,切面是通过使用常规类(基于模式的方法)或使用@Aspect注释的常规类(@AspectJ样式)来实现的。
通俗点来说,我们在项目中使用到的事务管理,例如我在add方法中需要新增一条用户,可是我自己并不想来进行实物的开启,关闭,或者说是异常时的回滚操作。那么我可以定义一个切面,对这个方法进行拦截,只要是涉及到add的方法,你的事务控制交给我来管了,你只要负责你的新增操作即可。而DAO层算是一个大的模块了吧。我们可以通过带有@Aspect注解的常规类来实现对某一个模块进行切面编程。
@Aspect public class LogAspect { //具体需要对该模块进行怎样的增强 }
我们知道了如何定义一个切面来拦截某一个模块。那我们怎么才能让这个切面知道,我要拦截的是项目的DAO层呢?接下来我们来看下Spring是如何来指定这个模块的。
Pointcut
翻译过来,叫做切入点,首先看下Spring官网是如何给出解释的。切入点:匹配连接点的谓词。通知与切入点表达式相关联,并在与切入点匹配的任何连接点上运行(例如,执行具有特定名称的方法)。连接点由切入点表达式匹配的概念是AOP的核心,Spring默认使用AspectJ切入点表达式语言。
通俗的说,Pointcut就是用来设定切面切入的范围,Spring中说到了切点表达式,我们可以通过配置表达式来指定切入范围。例如@Pointcut("execution( * com.xxx.xxx.add(..))")。那么Spring就会为com.xxx.xxx包下,所有的add方法进行增强。
@Aspect public class LogAspect { //指定具体的切点表达式 public static final String POINT_CUT = "execution(* com.xxx.xxx.add(..))"; }
这里已经讲明白了切入点的概念,那么增强的功能在何时才能生效呢?很明显,只有在我们具体的使用场景才会生效。而我们在上一篇文章中详细的介绍了代理模式的三种实现方式。要想在不改变原功能的前提下,完成对原功能的功能增强。需要对目标对象进行代理。所以此时在实际调用的过程中实则是代理对象invoke的调用逻辑,或者cglib中的intercept的调用逻辑。而这每一个实际的调用过程被称之为连接点。
Join point
翻译过来,叫做连接点,先看下Spring官方是如何做出解释的。连接点:程序执行过程中的一个点,如方法的执行或异常的处理。在Spring AOP中,连接点总是表示方法执行。
public interface UserService { void save(User user); void update(User user); } public class LoginServiceImpl { @Autowired private UserService userService; public void login(){ ?/此处涉及到方法的调用 userService.save(); } }
不难看出,假设当前被注入的userService对象是在切点拦截范围内,那么此时注入的肯定为代理对象。当调用到save方法时,肯定会被增强,这就是一个连接点。即每一个具体的方法执行。
Advice
翻译过来,叫做通知,也可算是一个拦截器。先看下Spring官方是如何做出解释的。通知:切面在特定连接点上采取的操作。不同类型的通知包括“before”、“after”、“around”等通知。将通知建模为拦截器,并维护围绕连接点的拦截器链。
@Aspect public class LogAspect { //指定具体的切点表达式 public static final String POINT_CUT = "execution(* com.xxx.xxx.add(..))"; @Before(POINT_CUT) public void before(){ System.out.println("-----------------开启事务"); } @After(POINT_CUT) public void after() { System.out.println("-----------------关闭事务"); } @AfterThrowing(POINT_CUT) public void throwing() { System.out.println("-----------------事务回滚"); } }
此处仍然以事务管理为例,比如调用add方法时,会首先开启事务调用before方法,然后再执行add方法本身的逻辑。如果执行成功,最后会关闭事务调用after方法,如果执行失败,则调用throwing方法进行事务回滚。这整个执行过程被称之为拦截器链,最后会按照此顺序依次执行。
AOP Proxy
Aop Proxy分为两类:JDK动态代理和Cglib动态代理。由此对象来执行整个方法的拦截器链。在Spring中,默认是使用JDK动态代理的,因为我们的Service层是主要的业务实现层,是主要涉及需要增强的地方。而service层都是基于接口而来。而cglib是通过动态创建子类代理对象来实现增强。如果你想使用cglib代理,那么你需要在<aop:aspectj-autoproxy>标签中配置proxy-target-class=true。
Weaving
官方术语叫织入,何为织入。通俗来说,围绕how,when,where展开,在什么地方什么时候需要做什么。织入就是通过代理对象在切面涉及的范围内动态的讲拦截器织入到目标方法中。何为动态,你可以理解为运行时,即方法执行时。
AOP各术语的关联关系
有了以上术语的基础,相信会对Spring的工作流程的理解有很大的帮助,下面我大致画了下流程图,帮助大家更好的理解。
应该算是涵盖了上面所有的术语,这个流程图可以看出他们是如何分工协作的。今天的内容就介绍到这了,下一篇文章我会正式开始进入源码分析阶段,看看在Spring中,是如何开启AOP的。感兴趣的可以持续关注我的AOP系列博文,谢谢大家!