SpringBoot自定义注解配合AOP
自定义注解
package com.example.servlet;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Author: CQ
* @Date: 2020/11/19 10:46
*/
// 此注解的使用位置
@Target(ElementType.METHOD)
//该@Chec的生命周期
@Retention(RetentionPolicy.RUNTIME)
public @interface MySysLog {
String decipher();
int length();
/**
* String: 数据类型,
* paramValues(): 参数名称,大括号是格式标准;
**/
String[] paramValues();
/**
* default: 默认的提示信息
**/
String message() default "参数不为指定值";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
注解解释
@Target
-
该注解用于@Check注解上,可以表明Check注解的使用位置,下面是Target中的
ElementType
的释义 -
当@Target中的参数为那个字段时,表明这个注解只能使用在什么位置 ElementType.TYPE:说明该注解只能被声明在一个类前。 ElementType.FIELD:说明该注解只能被声明在一个类的字段前。 ElementType.METHOD:说明该注解只能被声明在一个类的方法前。 ElementType.PARAMETER:说明该注解只能被声明在一个方法参数前。 ElementType.CONSTRUCTOR:说明该注解只能声明在一个类的构造方法前。 ElementType.LOCAL_VARIABLE:说明该注解只能声明在一个局部变量前。 ElementType.ANNOTATION_TYPE:说明该注解只能声明在一个注解类型前。 ElementType.PACKAGE:说明该注解只能声明在一个包名前
@Retention
-
该注解用于@Check注解上,可以表明Check注解的生命周期,下面是Retention中
RetentionPolicy
的释义 -
当@Retention中的参数为那个字段时,表明这个注解的可用范围 RetentionPolicy.SOURCE: 注解只保留在源文件中 RetentionPolicy.CLASS : 注解保留在class文件中,在加载到JVM虚拟机时丢弃 RetentionPolicy.RUNTIME: 注解保留在程序运行期间,此时可以通过反射获得定义在某个类上的所有注解。
AOP切面
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import com.example.demo.annotation.MySysLog;
import lombok.extern.slf4j.Slf4j;
/**
* @author CQO
* @since 2023/03/12 13:52
*/
@Slf4j
@Aspect
@Component
public class SystemLogAspect {
/**
* <P>拦截使用@MySysLog注解的方法</P>
* @param point
* @param mySysLog 自定义注解
* @return
* @throws Throwable
*/
@Around("@annotation(mySysLog)")
public Object around(ProceedingJoinPoint point, MySysLog mySysLog) throws Throwable {
MethodSignature signature = (MethodSignature)point.getSignature();
MySysLog annotation = signature.getMethod().getAnnotation(MySysLog.class);
String decipher = annotation.decipher();
int length = annotation.length();
System.out.println("获取注解上传入的参数: "+decipher +" "+length);
/**
* 在这里有一个问题,那就是如何动态的获取注解上的参数,
* 有一个思路就是可以看看Spring中@Valve是怎么获取配置文件的参数
*/
String name = point.getTarget().getClass().getName();
System.out.println("被切面的类相对路径: "+name);
String name1 = signature.getName();
System.out.println("被切面的类名: "+name1);
Object[] args = point.getArgs();
System.out.println("切面传入的参数:"+args);
return point.proceed();
}
}
测试注解和AOP
Controller
import com.example.demo.annotation.MySysLog;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author CQO
* @since 2023/03/12 13:53
*/
@RequestMapping("logAspect")
@RestController
public class MySystemLogAspectController {
@MySysLog(decipher = "ChenQ",length = 28)
@PostMapping("test")
public void MySystemLogAspectControllerTest(@RequestBody UserAspectTest userAspectTest){
System.out.println(userAspectTest);
}
}
实体类
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
/**
* @author CQO
* @since 2023/03/12 14:18
*/
@Getter
@Setter
@EqualsAndHashCode
public class UserAspectTest {
private String name;
private String age;
}
输出结果
tips
- 如果注解只能用于字段上的获取方式
package com.example.demo.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author CQO
* @since 2023/03/07 16:42
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyFiled {
String decipher();
int length();
}
package com.example.demo.annotation;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Field;
/**
* @author CQO
* @since 2023/03/07 16:45
*/
public class MyFiledTest {
@MyFiled(decipher = "用户名", length = 12)
private String userName;
@MyFiled(decipher = "用户名", length = 12)
private String user;
@Test
public void test() {
Class<MyFiledTest> myFiledTestClass = MyFiledTest.class;
Field[] declaredFields = myFiledTestClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
// 判断这个字段是否有MyFile注解
if (declaredField.isAnnotationPresent(MyFiled.class)) {
MyFiled annotation = declaredField.getAnnotation(MyFiled.class);
System.out.println("字段: " + declaredField.getName() + " 姓名: " + annotation.decipher() + " 长度: "
+ annotation.length());
// 字段: userName 姓名: 用户名 长度: 12
// 字段: user 姓名: 用户名 长度: 12
}
}
}
}