接下来我们要聊的就是Spring核心之一的AOP,在第一篇里面,我已经大概描述了一点关于AOP的概念。接下来我们就来仔细的研究一下AOP的主要作用吧。
1 面向切面编程的概念
先来一段术语
在软件业,AOP为Aspect Oriented Programming的缩写,意为:[面向切面编程],通过[预编译]方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是[OOP]的延续,是软件开发中的一个热点,也是[Spring]框架中的一个重要内容,是[函数式编程]的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的[耦合度]降低,提高程序的可重用性,同时提高了开发的效率。在我的理解,简单翻译一下,就是在不改变原有对象功能的情况下让这个对象变得更牛逼,并且这对于这个对象本身来说他是感知不到的,也就是说可以非侵入的增强这个对象。具体到应用的层面上一般作用呢比如日志,权限,事务的管理等。
2 AOP的术语
aop自身有一些专业的术语,虽然我没怎么弄明白,这里先粘贴一下,大概说一下这些术语的意思吧。
通知(advice
):
定义了切面是什么以及何时使用,除了描述切面需要做的事,还解决了何时执行这个工作的问题,Spring的切面可以应用到5种类型的通知(前置通知(Before),后置通知(After),返回通知(After-return),异常通知(After-throwing),环绕通知(Around))后面我们会在代码中尝试使用。
连接点(Join point
):
连接点是在应用执行过程中能够插入切面的一个点。
切点(PointCut
):
通知具体到某一个点,切点定义了『何处』。
切面(Aspect
):
通知和切点的结合,可以理解为具体要给目标对象增强的对象。
引入(Introduction
):
引入允许我们向现有的类添加新方法或者属性。
织入(Weaving
):
织入是指把切面用于到目标对象并创建新的代理对象的过程。
大概了解了这些东西之后我们来是用代码来进一步了解这些术语的意思吧。
3 代码实现
我们先来定义一个Performance接口表示表演
/**
* 这是一个表演接口
*/
public interface Performance {
void perform();
}
这是一个表演接口,可以是任意表演形式的实现比如舞台剧,电影等等。
接下来我们再定义一个切面,假如切面就是观众,就演出本身来说,观众并不是他的核心,但是观众又很重要,所以在这里将观众声明成一个切点。
package com.crazytd.springstaff.aop;
import org.aspectj.lang.annotation.*;
@Aspect
public class Audience {
/**
* 切点的定义
*/
@Pointcut("execution(** com.crazytd.springstaff.aop.Performance.perform(..))")
public void performace(){}
/**
* 前置通知的定义,表演之前
*/
@Before("performace()")
public void silenceCellPhone(){
System.out.println("silence the cell phone");
}
/**
* 前置通知的定义,表演之前
*/
@Before("performace()")
public void takeSeat(){
System.out.println("take a seat");
}
/**
* 前置通知的定义,表演之后
*/
@AfterReturning("performace()")
public void applause(){
System.out.println("such a grate perform");
}
/**
* 出现意外的时候
*/
@AfterThrowing("performace()")
public void demandRefund(){
System.out.println("demand a refund");
}
}
值得注意的是,这个观众类依然是一个pojo,我们还是能像其他pojo一样调用,只不过是通过注解表明他是一个切面罢了。
当然切面和切点都定义好了还是不能直接应用的,因为这样的话他还是一个Spring管理的普通bean,并没有赋予切面的功能,我们还需要再javaconfig里面通过@EnableAspectJAutoProxy注解来启用自动代理功能,代码如下
@Configuration
@EnableAspectJAutoProxy 这里启用了AspectJ的自动代理
@ComponentScan
public class ConcertConfig {
@Bean 声明Audience这个bean
public Audience audience(){
return new Audience();
}
}
测试打印结果:
silence the cell phone
take a seat
这是一台美妙的音乐剧
such a grate perform
(测试是在spring的junit测试环境中进行的,第一次我是在方法里面new 了一个concert对象,发现通知并没有被织入,然后通过autowired来注入进来才可以,说明这必须是spring管理的bean才可以被插入advice)
在这里我们演示了前几种advice的方式,还剩下最后一种,环绕通知,这相当于将其他几个通知的能力加起来一起用,接下来我们用代码来演示。
4 环绕通知
我们需要把这个切面改写一下,如下
@Aspect
public class AudienceTwo {
/**
* 切点的定义
*/
@Pointcut("execution(** com.crazytd.springstaff.aop.Performance.perform(..))")
public void performace(){}
@Around("performace()")
public void watchingPerform(ProceedingJoinPoint joinPoint){
try {
System.out.println("请关闭手机");
System.out.println("请入座");
joinPoint.proceed();
System.out.println("鼓掌,牛批");
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
}
这就让切面的定义更加的简洁明了。
这样基本就把切面的一些基本操作演示完了,下一篇我们将继续研究aop的其他内容