前置知识
- 需要用到的几个元注解
- springboot 中如何使用aop
步骤
1、依赖
因为需要使用到springboot框架和aop技术,并且最后的测试用的是单元测试,因此需要引入以下依赖
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
2、定义注解
定义注解需要用到Java中的元注解,具体使用需要看自己的业务而定,并且注解中可以加入字段。
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface LearnAnnotation {
public String desc() default "";
}
3、编写aop实现类
利用aop使自定义的注解生效
@Aspect
@Component
public class LearnAop {
@Pointcut("@annotation(org.example.myAnnotation.LearnAnnotation)")
private void cut(){}
@Around("cut()")
public void advice(ProceedingJoinPoint joinPoint) throws Throwable {
// 获取连接点方法运行时的入参
Object[] args = joinPoint.getArgs();
// 获取目标方法所在的对象信息
Class<?> targetClass = joinPoint.getTarget().getClass();
// 获取连接点方法对象
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
// 获取目标方法名称
String methodName = signature.getName();
// 获取目标方法信息
Method targetMethod = targetClass.getDeclaredMethod(methodName,signature.getParameterTypes());
// 获取自定义注解信息
LearnAnnotation annotation = targetMethod.getAnnotation(LearnAnnotation.class);
joinPoint.proceed();
}
}
4、使用自定义注解并验证是否成功
使用
@Component
public class LearnServer {
@LearnAnnotation
public void test1(String args){
System.out.println(args);
}
}
验证
@SpringBootTest
@RunWith(SpringRunner.class)
public class MainTest {
@Autowired
private LearnServer learnServer;
@Test
public void test1(){
learnServer.test1("123");
}
}
解释
1、常用的元注解
- @Retention:指定其所修饰的注解的保留策略
- @Document:该注解是一个标记注解,用于指示一个注解将被文档化
- @Target:用来限制注解的使用范围
- @Inherited:该注解使父类的注解能被其子类继承
@Retention 用于表明注解保留在Java运行的哪个阶段,其中有三个可选择的值
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
* 编译阶段
*/
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
* 由编译器记录在类文件中,但是不保存在运行阶段,默认字段
*/
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
* 编译和运行阶段都保留
*/
RUNTIME
}
@Document:可以被javadoc识别并提取成文档 @Target:注解可以在哪些地方使用,可以选择多个
public enum ElementType {
/** Class, interface (including annotation type), or enum declaration */
TYPE,
/** Field declaration (includes enum constants) */
FIELD,
/** Method declaration */
METHOD,
/** Formal parameter declaration */
PARAMETER,
/** Constructor declaration */
CONSTRUCTOR,
/** Local variable declaration */
LOCAL_VARIABLE,
/** Annotation type declaration */
ANNOTATION_TYPE,
/** Package declaration */
PACKAGE,
/**
* Type parameter declaration
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* Use of a type
*
* @since 1.8
*/
TYPE_USE
}
@Inherited:假如父类使用了@Inherited修饰的注解,那么子类也自动使用父类的注解
2、aop类的编写
定义切点,并且切点指向自定义的注解,使用的是@annotation注解,其他的业务逻辑就是aop的使用方法。其中可以通过ProceedingJoinPoint对象获取注解的属性并进行操作。