AOP简介
AOP的底层原理是动态代理。
AOP也就是面向切面,意思是做出一些通用的功能,如打印日志等,应用于所有需要的地方。传统的面向对象,在每个对象里进行打印日志,重复且无意义。
AOP实现的思路,拦截住一些需要使用打印日志功能的方法,使用动态代理,对原本的方法加入了打印日志的操作。
AOP重要概念
- 通知(增强,Advice):需要添加的功能叫做通知,比如说打印日志的操作
- 连接点(Join point):就是允许使用通知的地方,基本上每个方法前、后、抛异常时都可以是连接点(也就是before、after)
- 切点(Poincut):需要添加新功能的地方,比如需要在类A的方法 f() 前后打印日志, f() 就是切点
- 切面(Aspect):其实就是通知和切点的结合,通知和切点共同定义了切面的全部内容,它是干什么的,什么时候在哪执行
- 引入(Introduction):在无需修改现有类的前提下,让它们具有新的行为和状态。针对方法,而织入重点是实现方式为代理,针对对象。
- 目标(target):被通知的对象。也就是需要加入额外代码的对象,也就是真正的业务逻辑被组织织入切面。
- 织入(Weaving):把切面加入程序代码的过程。切面在指定的连接点被织入到目标对象中,在目标对象的生命周期里有多个点可以进行织入:编译期(切面在目标类编译时被织入,这种方式需要特殊的编译器)、类加载期(切面在目标类加载到JVM时被织入,这种方式需要特殊的类加载器,它可以在目标类被引入应用之前增强该目标类的字节码)、运行期(切面在应用运行的某个时刻被织入,一般情况下,在织入切面时,AOP容器会为目标对象动态创建一个代理对象,Spring AOP就是以这种方式织入切面的)
AOP具体使用方法
先定义一个切点,也就是需要拦截的地方。
围绕着切点,进行日志打印,共有五种执行日志打印的时机:
- before(前置通知): 在方法开始执行前执行
- after(后置通知): 在方法执行后执行
- around(环绕通知): 在方法执行前和执行后都会执行(优先于before和after)
- afterReturning(返回后通知): 在方法返回后执行
- afterThrowing(异常通知): 在抛出异常时执行
AOP的具体使用方法见:
传送门
拦截的东西
package com.aili.poem.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class LoveController {
@RequestMapping(value = "sayLove")
@ResponseBody
/**
* 这里必须加@ResponseBody,否则会出现白页
*/
public String sayLove(String name){
System.out.println("方法运行,参数为:" + name);
return "求爱";
}
}
拦截后进行的操作
@Aspect
@Component
public class ControllerAspect {
//切点
@Pointcut("execution(* com.aili.poem.controller..*(..))")
public void pointcut(){
}
//开始之前做点事
@Before("pointcut()")
public void doSomethingBefore(JoinPoint joinPoint){
//获取参数
Object[] args = joinPoint.getArgs();
System.out.println("开始对" + args[0].toString() + "进行爱");
System.out.println("Do Some Foreplay");
System.out.println("Kiss your partner");
System.out.println("Fingering your partner");
}
//结束之后做点事
@After("pointcut()")
public void doSomethingAfter(){
System.out.println("Wipe the white liquid away");
}
//前后都做点事(在最前面)
//这里注意必须返回Object
@Around("pointcut()")
public Object doSomethingAround(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("love you,baby");
//在这条语句之前,相当于@Before,之后则相当于@After
Object obj = joinPoint.proceed();
System.out.println("love you,baby");
return obj;
}
//返回结果后做点事
@AfterReturning(value = "pointcut()", returning = "returnValue")
public void doSomethingAfterReturn(JoinPoint joinPoint, Object returnValue){
//获取参数
Object[] args = joinPoint.getArgs();
System.out.println("完成对" + args[0].toString() + "的爱");
System.out.println("对她进行了" + returnValue.toString());
}
//出现意外做点事
@AfterThrowing("pointcut()")
public void doSomethingAfterThrow(){
System.out.println("开车失败");
}
}
最终执行的结果
love you,baby
开始对女神进行爱
Do Some Foreplay
Kiss your partner
Fingering your partner
方法运行,参数为:女神
love you,baby
Wipe the white liquid away
完成对女神的爱
对她进行了求爱