AOP: Aspect Oriented Programming 面向切面编程
这个概念听起来有点抽象,说通俗一点,就是在程序运行期间,在不修改原有代码的情况下,增强跟主要业务没有关系的公共功能代码(无侵入),到之前写好的方法中的指定位置.
1.添加pom依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
2.配置xml文件(因为我的这个是一个ssm整合的project,所以直接就在springmvc.xml中添加了)
3.编写切面类
package com.cctv.util;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Component
@Aspect
public class LogUtil {
@Before("execution(* com.cctv.service..*.*(..))")
public static void before(JoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
String name = joinPoint.getSignature().getName();
System.out.println("param: "+ Arrays.asList(args));
System.out.println("method: "+name);
System.out.println("方法前");
}
// 后置通知
@After("execution(* com.cctv.service..*.*(..))")
public static void after(){
System.out.println("方法后");
}
// 后置异常通知
@AfterThrowing("execution(* com.cctv.service..*.*(..))")
public static void afterException(){
System.out.println("方法异常");
}
// 后置返回通知
@AfterReturning("execution(* com.cctv.service..*.*(..))")
public static void afterEnd() {
System.out.println("方法返回");
}
}
使用AOP必须添加@Component和@Aspect注解
@Before: 在目标方法之前运行
@After: 在目标方法之后运行
@AfterReturing: 在目标方法正常返回之后运行
@AfterThrowing: 在目标方法抛出异常之后运行
这里就有一个疑问,所谓目标方法是什么呢?其实就是execution表达式所指的.
这是运行了tomcat服务器,发送了某一个请求,首先会经过Controller层,然后到达Service层,由于execution表达式设置了会对Service层的所有类所有方法,所以会先触发@Before中的方法,接着就会走到Mapper层,在Mapper层把方法执行完毕之后,就会执行@After和@AfterReturing中的方法.
这里提一下AOP实现原理,是JDK动态代理和cglib代理.
如果是一个接口且有实现类,就会触发底层JDK动态代理,如果是一个类,没有子类,就会触发cglib代理.图中的Bean都是对应子类.
SpringMVC拦截器
1.自定义一个拦截器,并且实现HandlerInterceptor,重写perHandle,postHandle,afterCompletion三个方法.
2.配置xml文件
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/login"/>
<bean class="com.cctv.interceptor.CheckLoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
上图代表拦截所有的路径,除了/login.
执行顺序: 拦截器preHandle-->执行目标方法-->拦截器postHandle-->执行页面跳转-->拦截器afterCompletion方法
dispatcherServlet-->preHandle-->controller-->postHandle(在return ModelAndView之前执行,可以修改ModelAndView的值)
-->afterCompletion(在Controller的return之后,但是在filter之前)
如果preHandle方法返回false,意味着不放行,后续所有操作会中断,如果执行方法出现异常,后续流程不会执行,但是afterCompletion会执行.
如果有多个拦截器,执行顺序按照配置顺序:
preHandle按照顺序执行
postHandle按照逆序执行
afterCompletion按照逆序执行
关于 过滤器, 拦截器, AOP三者的执行顺序大致如下图