使用Spring AOP必须添加AOP的依赖包,并配置AOPjava
<!--
只须要导入 spring-webmvc 这一个包,maven就会自动下载如下依赖包
spring-core —— Spring的核心组件
spring-beans —— SpringIoC(依赖注入)的基础实现
spring-aop ——Spring的面向切面编程,提供AOP(面向切面编程)实现
spring-context —— Spring提供在基础IoC功能上的扩展服务
spring-expression —— Spring表达式语言
spring-web —— SpringMVC支持WEB端应用部署架构
spring-webmvc —— REST Web服务和Web应用的视图控制器的实现
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- aop aspect 相关jar包-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
复制代码
<!-- 激活Spring组件扫描功能,自动扫描指定包及其子包下面经过注解配置的组件 -->
<context:component-scan base-package="com.test.aop"/>
<!-- 启动AspectJ支持proxy-target-class="true"指定spring使用cglib来生成代理方法。
不填Spring则根据条件从cglib和java动态代理中选择 -->
<aop:aspectj-autoproxy proxy-target-class="true" />
复制代码
<!-- 只须要导入这个包,Maven就会下载如下依赖包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
复制代码
因为用的是SpringBoot,因此也不须要配置aopweb
// 匹配service类里头的全部方法
@Pointcut("within(com.test.service)")
public void matchType(){}
// 匹配com.test包及子包下全部类的方法
@Pointcut("within(com.test..*)"
public void matchPackage(){}
复制代码
/**
* @annotation 匹配方法级别
* 以下,匹配 标注有 @ToExcel注解 的方法
*/
@Pointcut("@annotation(com.demo.security.ToExcel)")
public void annotation(){}
复制代码
/**
* @within 匹配类级别
* 非 Spring环境下,要求的 annotation 的 RetentionPolicy 级别为 CLASS
* 以下,匹配 标注有 @Service注解 的类 的全部方法
*/
@Pointcut("@within(org.springframework.stereotype.Service)")
public void within(){}
复制代码
/**
* @target 匹配类级别
* 非 Spring环境下,要求的 annotation 的 RetentionPolicy 级别为 RUNTIME
* 以下,匹配 标注有 @Service注解 的类 的全部方法
*/
@Pointcut("@target(org.springframework.stereotype.Service)")
public void target(){}
复制代码
/**
* @args 匹配参数级别
* 以下,匹配 某方法的参数 所属的类 标注有 authority注解 的方法
* 即,被拦截的方法的参数中,有的参数所属的类 标注有 authority注解
*/
@Pointcut("@args(com.test.authority)")
public void args(){}
复制代码
// ps:这个还没弄清楚,就不误人子弟了
@Pointcut("this(com.test.DemoDao)")
public void thisDemo() {}
复制代码
// ps:这个还没弄清楚,就不误人子弟了
@Pointcut("target(com.test.IDao)")
public void targetDemo() {}
复制代码
// 匹配 Spring bean 容器中,全部名称以 Service 结尾的 bean
@Pointcut("bean(*Service)")
public void beanDemo() {}
复制代码
//匹配任何名称以 find 开头并且只有一个 Long 参数的方法
@Pointcut("execution(* *..find*(Long))")
public void execution1() {
}
//匹配任何名称以 find 开头的并且第一个参数为 Long 类型的方法
@Pointcut("execution(* *..find*(Long,..))")
public void execution2() {
}
复制代码
//匹配任何 只有一个Long参数 的方法
@Pointcut("args(Long)")
public void args1() {
}
//匹配第一个参数为 Long 类型的方法
@Pointcut("args(Long,..)")
public void args2() {
}
复制代码
execution(<修饰符>? <返回值类型> <方法>(<参数列表>) <异常>?)spring
/**
* execution(<修饰符>? <返回值类型> <方法>(<参数列表>) <异常>?)
* 以下,
* 匹配 修饰符为 public,
* 返回值类型为任意类型,
* 方法为 com.test.service包中 以Service结尾的类的因此方法,
* 参数列表为任意参数,
* 异常为java.lang.IllegalAccessException
* 注意,若是指定了异常,那么只会匹配 throws 了 指定异常的方法!!!
*/
@Pointcut("execution(public * com.test.service.*Service.*(..) throws java.lang.IllegalAccessException)")
public void execution() {
}
复制代码
做用: 定义一个切入点express
@Pointcut()注解的value参数: 一个切面表达编程
/**
* @Pointcut 注解,用于定义一个织入点
*
* 以下,
* 匹配 修饰符为 public,
* 返回值类型为任意类型,
* 方法为 com.test.service包中 以Service结尾的类的因此方法,
* 参数列表为任意参数,
* 异常为java.lang.IllegalAccessException
*
* 的方法为织入点
*/
@Pointcut("execution(public * com.test.service.*Service.*(..) throws java.lang.IllegalAccessException)")
public void log() {}
复制代码
做用: 被打上 @Before 注解的方法,会在目标方法执行以前执行bash
@Before()注解的value参数: 除了是一个切面表达式以外,还能够是一个定义好的织入点架构
/**
* @Before 注解的参数 能够是一个切面表达式,也能够是一个织入点
* 以下,是一个名为log()的织入点
* 此@Before注解 将匹配log()织入点匹配到的方法
*/
@Before("log()")
public void before(){
System.out.println("此语句输出在目标方法执行以前");
}
复制代码
做用: 被打上 @After 注解的方法,会在目标方法执行以后执行,无论目标方法是否成功执行或抛出异常mvc
@After()注解的value参数: 除了是一个切面表达式以外,还能够是一个定义好的织入点maven
/**
* @After 注解的参数 能够是一个切面表达式,也能够是一个织入点
* 以下,此@After 将匹配log()织入点 或 切面表达式匹配到的方法
*/
@After("log() || @annotation(com.demo.security.ToExcel)")
public void After(){
System.out.println("此语句输出在目标方法执行以后");
}
复制代码
做用: 被打上 @After 注解的方法,会将目标方法“包围”起来, 在目标方法执行先后作一些操做spring-boot
@Around()注解的value参数: 除了是一个切面表达式以外,还能够是一个定义好的织入点
/**
* 打上 @After 注解的方法,会将目标方法“包围”起来,在目标方法执行先后作一些操做
* 以下,将匹配log()织入点中方法参数名为 token 的方法
* 并将此token参数 和 ProceedingJoinPoint对象 做为入参
*/
@Around(value = "log() && args(token)")
public Object Around(ProceedingJoinPoint joinPoint, String token) throws Throwable {
System.out.println("拦截方法的token参数值为:" + token);
System.out.println("此语句输出在目标方法执行以前");
try {
// 执行目标方法,并返回目标方法的执行结果
Object result = joinPoint.proceed(joinPoint.getArgs());
return result;
} catch (Throwable throwable) {
System.out.println("出现异常");
// 若是目标方法出现异常,不要`生吞`异常,最好原样抛出
throw throwable;
} finally {
// @After注解 至关于 finally的语句,无论目标方法是否成功执行或抛出异常,都会执行
System.out.println("此语句输出在目标方法执行以后");
}
}
复制代码
做用: 此注解与@After注解做用同样,不一样之出在于它多了一个 returning参数,能够用来获取目标方法返回值,并做为入参带入方法中
@AfterReturning()注解的value参数: 除了是一个切面表达式以外,还能够是一个定义好的织入点
/**
* 使用 returning 获取目标方法返回值,并取名为result,再将result做为参数带入方法中
*/
@AfterReturning(value = "log() || @annotation(com.demo.security.ToExcel)", returning = "result")
public void AfterReturning(Object result) {
// 打印目标方法返回结果
System.out.println(result);
System.out.println("此语句输出在目标方法执行以后");
}
复制代码
做用: 此注解不一样于@After注解,它只有在目标方法抛出异常以后才会执行
@AfterThrowing()注解的value参数: 除了是一个切面表达式以外,还能够是一个定义好的织入点
/**
*使用 throwing 获取目标方法抛出的异常,并取名为e,再将 e 做为参数带入方法中
*/
@AfterThrowing(value="log()", throwing="e")
public void AfterThrowing(Exception e){
//处理异常
e.getMessage();
System.out.println("此方法在 目标方法抛出异常时 才执行");
}
复制代码
首先建立一个java类,而后打上 @Aspect 和 @Component 注解,一个切面就定义好了。
package com.example.demo;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* 自定义切面须要在类上面打上两个注解
*
* @Aspect注解 用于标识这个类是一个自定义切面
* @Component注解 用于将此类交给 Spring 管理
*/
@Aspect
@Component
public class Test {
/**
* @Pointcut 注解,用于定义一个织入点
* <p>
* 以下,
* 匹配 修饰符为 public,
* 返回值类型为任意类型,
* 方法为 com.test.service包中 以Service结尾的类的因此方法,
* 参数列表为任意参数,
* 异常为java.lang.IllegalAccessException
* <p>
* 的方法为织入点
*/
@Pointcut("execution(public * com.test.service.*Service.*(..) throws java.lang.IllegalAccessException)")
public void log() {
}
/**
* 打上 @Before 注解的方法,会在目标方法执行以前执行
*
* @Before 注解的参数 能够是一个切面表达式,也能够是一个织入点
* 以下,是一个名为log()的织入点
* 此@Before注解 将匹配log()织入点匹配到的方法
*/
@Before("log()")
public void before() {
System.out.println("此语句输出在目标方法执行以前");
}
/**
* 被打上 @After 注解的方法,会在目标方法执行以后执行,无论目标方法是否成功执行或抛出异常
*
* @After 注解的参数 能够是一个切面表达式,也能够是一个织入点
* 以下,此@After 将匹配log()织入点 或 切面表达式匹配到的方法
*/
@After("log() || @annotation(com.demo.security.ToExcel)")
public void After() {
System.out.println("此语句输出在目标方法执行以后");
}
/**
* 打上 @After 注解的方法,会将目标方法“包围”起来,在目标方法执行先后作一些操做
* 以下,将匹配log()织入点中方法参数名为 token 的方法
* 并将此token参数 和 ProceedingJoinPoint对象 做为入参
*/
@Around(value = "log() && args(token)")
public Object Around(ProceedingJoinPoint joinPoint, String token) throws Throwable {
System.out.println("拦截方法的token参数值为:" + token);
System.out.println("@After此语句输出在目标方法执行以前");
try {
// 执行目标方法,并返回目标方法的执行结果
Object result = joinPoint.proceed(joinPoint.getArgs());
return result;
} catch (Throwable throwable) {
System.out.println("出现异常");
// 若是目标方法出现异常,不要`生吞`异常,最好原样抛出
throw throwable;
} finally {
// @After注解 至关于 finally的语句,无论目标方法是否成功执行或抛出异常,都会执行
System.out.println("此语句输出在目标方法执行以后");
}
}
/**
* 使用 returning 获取目标方法返回值,并取名为result,再将result做为参数带入方法中
*/
@AfterReturning(value = "log() || @annotation(com.demo.security.ToExcel)", returning = "result")
public void AfterReturning(Object result) {
// 打印目标方法返回结果
System.out.println(result);
System.out.println("此语句输出在目标方法执行以后");
}
/**
* 使用 throwing 获取目标方法抛出的异常,并取名为e,再将 e 做为参数带入方法中
*/
@AfterThrowing(value = "log()", throwing = "e")
public void AfterThrowing(Exception e) {
//处理异常
e.getMessage();
System.out.println("此方法在 目标方法抛出异常时 才执行");
}
}
复制代码