SpringBoot Aop切面
添加aop依赖
org.springframework.boot
spring-boot-starter-aop
定义切面,交给springboot 管理
非注解方式定义切点
package com.example.demo.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* @Description TODO
* @Author coderOx
* @Date 2023/1/6 21:13
*/
@Aspect //注解类
@Component //交给spring管理
public class MyAspect {
//切点信息
//value为切点的路径名称,controller包下的所有类的所有方法包括参数
@Pointcut(value = "execution(* com.example.demo.controller.*.*(..))")
public void pointCut(){};
//执行切点之前
@Before(value = "pointCut()")//value为切点方法
public void before(JoinPoint joinPoint){
System.out.println("切点执行前"+joinPoint);
}
//执行切点之后
@After(value = "pointCut()")//value为切点方法
public void after(JoinPoint joinPoint){
System.out.println("切点执行后 "+joinPoint );
}
//环绕切点执行
@Around(value = "pointCut()")//value为切点方法
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
long begin = System.currentTimeMillis();
System.out.println("环绕前" + joinPoint);
//执行切点方法并且获取切点的数据,一定要写,否则切点方法无法执行
Object o = joinPoint.proceed();
System.out.println("环绕后");
System.out.printf("环绕执行时间:--->{%d}",System.currentTimeMillis()-begin);
//返回执行切点方法的数据,一定要写,否则方法返回值会丢失
return o;
}
//切点方法返回数据之后执行
//value为切点方法,o为此方法afterReturning的参数o值为被执行方法的返回值
@AfterReturning(value = "pointCut()",returning = "o")
public void afterReturning(JoinPoint joinPoint,Object o){
System.out.println("返回值执行后"+joinPoint);
System.out.println("afterReturning-value:"+joinPoint);
}
//value为切点方法,throw为异常返回信息
@AfterThrowing(value = "pointCut()",throwing = "e")
public void afterThrow(JoinPoint joinPoint,Exception e){
System.out.println("异常抛出后"+joinPoint);
System.out.println("afterThrow-e.message():"+e.getMessage());
}
}
TestController代码
package com.example.demo.controller;
import com.sun.org.glassfish.gmbal.ParameterNames;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.websocket.server.PathParam;
/**
* @Description TODO
* @Author coderOx
* @Date 2023/1/6 21:15
*/
@RestController
public class TestController {
@RequestMapping("/test/{arg}")
public String test(@PathVariable("arg") String arg){
System.out.println("test被执行参数:"+arg);
return "test + arg:"+arg;
}
@RequestMapping("/test2/{num}")
public String test2(@PathVariable("num") Integer num){
int i = 1/num;
return "test2";
}
}
执行http://localhost:8080/test/aaa结果
执行http://localhost:8080/test2/0结果
注解方式定义切点
定义注解
/**
* @Target({ElementType.PARAMETER, ElementType.METHOD})
* 作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
*
* 取值(ElementType)有:
*
* 1.CONSTRUCTOR:用于描述构造器
* 2.FIELD:用于描述域
* 3.LOCAL_VARIABLE:用于描述局部变量
* 4.METHOD:用于描述方法
* 5.PACKAGE:用于描述包
* 6.PARAMETER:用于描述参数
* 7.TYPE:用于描述类、接口(包括注解类型) 或enum声明
*
* @Retention(RetentionPolicy.RUNTIME) 解释:@Retention() 定义了该Annotation(注释)被保留的时间长短
* 取值(RetentionPoicy)有:
*
* 1.SOURCE:在源文件中有效(即源文件保留)
* 2.CLASS:在class文件中有效(即class保留)
* 3.RUNTIME:在运行时有效(即运行时保留)
*
*
* 自定义注解: @interface 自定义注解
*
* 定义注解格式:
* public @interface 注解名 {定义体}
*
* 注解参数的可支持数据类型:
*
* 1.所有基本数据类型(int,float,boolean,byte,double,char,long,short)
* 2.String类型
* 3.Class类型
* 4.enum类型
* 5.Annotation类型
* 6.以上所有类型的数组
*
* Annotation(注释)类型里面的参数该怎么设定:
* 第一,只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型;
* 第二,参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和
* String,Enum,Class,annotations等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String;
* 第三,如果只有一个参数成员,最好把参数名称设为"value",后加小括号.例:下面的例子FruitName注解就只有一个参数成员。
*
*/
package com.example.demo.aspect;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(value = ElementType.METHOD)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface PointCutAnnotation {
String methodName() default "";
}
更改切面中切点的注解值,其他同非注解方式
package com.example.demo.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* @Description TODO
* @Author coderOx
* @Date 2023/1/6 21:13
*/
@Aspect //注解类
@Component //交给spring管理
public class MyAspect {
//切点信息
//value为切点的路径名称,controller包下的所有类的所有方法包括参数
// @Pointcut(value = "execution(* com.example.demo.controller.*.*(..))")
@Pointcut(value = "@annotation(com.example.demo.aspect.PointCutAnnotation)")
public void pointCut(){};
//执行切点之前
@Before(value = "pointCut()")//value为切点方法
public void before(JoinPoint joinPoint){
System.out.println("切点执行前"+joinPoint);
}
//执行切点之后
@After(value = "pointCut()")//value为切点方法
public void after(JoinPoint joinPoint){
System.out.println("切点执行后 "+joinPoint );
}
//环绕切点执行
@Around(value = "pointCut()")//value为切点方法
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
long begin = System.currentTimeMillis();
System.out.println("环绕前" + joinPoint);
//执行切点方法并且获取切点的数据,一定要写,否则切点方法无法执行
Object o = joinPoint.proceed();
System.out.println("环绕后");
System.out.printf("环绕执行时间:--->{%d}",System.currentTimeMillis()-begin); //返回执行切点方法的数据,一定要写,否则方法返回值会丢失
return o;
}
//切点方法返回数据之后执行
//value为切点方法,o为此方法afterReturning的参数o值为被执行方法的返回值
@AfterReturning(value = "pointCut()",returning = "o")
public void afterReturning(JoinPoint joinPoint,Object o){
System.out.println("返回值执行后"+joinPoint);
System.out.println("afterReturning-value:"+joinPoint);
}
//value为切点方法,throw为异常返回信息
@AfterThrowing(value = "pointCut()",throwing = "e")
public void afterThrow(JoinPoint joinPoint,Exception e){
System.out.println("异常抛出后"+joinPoint);
System.out.println("afterThrow-e.message():"+e.getMessage());
}
}
可以在指定通知指定切点,作为参数使用,比如@Before
package com.example.demo.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* @Description TODO
* @Author coderOx
* @Date 2023/1/6 21:13
*/
@Aspect //注解类
@Component //交给spring管理
public class MyAspect {
//切点信息
//value为切点的路径名称,controller包下的所有类的所有方法包括参数
// @Pointcut(value = "execution(* com.example.demo.controller.*.*(..))")
@Pointcut(value = "@annotation(com.example.demo.aspect.PointCutAnnotation)")
public void pointCut(){};
//执行切点之前
@Before(value = "@annotation(pointCutAnnotation)")//value为切点的类,可以作为参数在方法中使用
public void before(JoinPoint joinPoint,PointCutAnnotation pointCutAnnotation){
System.out.println("切点执行前"+joinPoint);
System.out.println("切点的注解值:"+pointCutAnnotation.methodName());
}
//执行切点之后
@After(value = "pointCut()")//value为切点方法
public void after(JoinPoint joinPoint){
System.out.println("切点执行后 "+joinPoint );
}
//环绕切点执行
@Around(value = "pointCut()")//value为切点方法
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
long begin = System.currentTimeMillis();
System.out.println("环绕前" + joinPoint);
//执行切点方法并且获取切点的数据,一定要写,否则切点方法无法执行
Object o = joinPoint.proceed();
System.out.println("环绕后");
System.out.printf("环绕执行时间:--->{%d}",System.currentTimeMillis()-begin);
//返回执行切点方法的数据,一定要写,否则方法返回值会丢失
return o;
}
//切点方法返回数据之后执行
//value为切点方法,o为此方法afterReturning的参数o值为被执行方法的返回值
@AfterReturning(value = "pointCut()",returning = "o")
public void afterReturning(JoinPoint joinPoint,Object o){
System.out.println("返回值执行后"+joinPoint);
System.out.println("afterReturning-value:"+joinPoint);
}
//value为切点方法,throw为异常返回信息
@AfterThrowing(value = "pointCut()",throwing = "e")
public void afterThrow(JoinPoint joinPoint,Exception e){
System.out.println("异常抛出后"+joinPoint);
System.out.println("afterThrow-e.message():"+e.getMessage());
}
}
controller类
执行http://localhost:8080/test/aaa结果