文章目录
- 0.前言
- 1.创建注解类
- 1.1.@Target(ElementType.XXX)
- 1.2.@Retention(RetentionPolicy)
- 1.3.@interface注解类
- 1.4.自定义参数
- 1.5.代码
- 2.创建切面类
- 2.1.@annotation(xxx)
- 2.2.代码
- 3.在对应的方法上加上注解
- 4.测试结果
- 5.进阶内容:代码计时器
- 5.1.注解类Timing
- 5.2.切面类TimingAspect
- 5.3.控制器StudentController
- 5.4.测试类AopLearningApplicationTests
- 5.5.测试结果
0.前言
项目:Learning.aop-learning[aop]
1.创建注解类
创建annotation包,在annotation包下创建注解类,类名就是注解名字
1.1.@Target(ElementType.XXX)
用于声明你自定义的这个注解(@Eshang)可能出现在java程序中的语法位置
- TYPE:类、接口、注解类上
- METHOD:方法上
- FIELD:字段上
- PARAMETER:参数声明
- CONSTRUCTOR:构造器声明
- LOCAL_VARIABLE:局部变量声明
- ANNOTATION_TYPE:注解类声明(这里只有注解类,普通类不行)
- PACKAGE:包声明
前四个是最常用,也是最常见的。
如果允许在多个地方出现,则该内容可以用大括号将其括起,
如@Target({ElementType.METHOD, ElementType.Type}) 表示注解能出现在类或方法上
1.2.@Retention(RetentionPolicy)
用于声明注解在何时有效
- RUNTIME:运行时有效
- CLASS:注解将被编译器在类文件中记录,但在运行时不需要JVM保留
- SOURCE:注解只在源代码保留,编译时将被忽略
同样的,如果允许多个地方出现,则可以用大括号将其括起。
1.3.@interface注解类
声明这是一个注解类。
1.4.自定义参数
使用注解时,可以在括号中对一些参数进行赋值
而这些参数最初便在这里定义。格式为:
//类型 参数名 default 默认值;
String value() default "Eshang";
若括号中没有写,则采用defaut后的默认值
1.5.代码
package com.eshang.aop.learning.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author xyx-Eshang
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Eshang {
String value() default "Eshang";
boolean admin() default false;
}
2.创建切面类
2.1.@annotation(xxx)
在@Around()的括号中写"@annotation(xxx)"
@Around("@annotation(eshang)")
public Object eshangAdvice(ProceedingJoinPoint pjp, Eshang eshang) throws Throwable{
...
}
里层括号分为两种情况:
- 未在形参中定义:写注解类的全限定名,此处为:
com.eshang.aop.learning.annotation.Eshang - 已在形参中定义:写形参
当然,也可以再连接execution(xxx)表达式,如
2.2.代码
package com.eshang.aop.learning.annotation;
import com.eshang.aop.learning.annotation.Eshang;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
/**
* @author xyx-Eshang
*/
@Aspect
@Component
public class EshangAspect {
@Around("@annotation(eshang)")
public Object eshangAdvice(ProceedingJoinPoint pjp, Eshang eshang) throws Throwable {
try {
System.out.println("自定义注解已被实现!");
Object result = pjp.proceed();
System.out.println("获取value为:" + eshang.value());
System.out.println("获取admin为:" + eshang.admin());
return result;
} catch (Exception e) {
System.out.println("发生异常,请重新检查代码!");
return null;
}
}
}
3.在对应的方法上加上注解
package com.eshang.aop.learning.controller;
import com.eshang.aop.learning.annotation.Eshang;
import com.eshang.aop.learning.annotation.Timing;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author xyx-Eshang
*/
@RestController
@RequestMapping("/student")
public class StudentController {
@Eshang(value = "LaLaLa")
@PostMapping("/testAop")
public void testAop() {
System.out.println("现在执行testAop方法");
}
}
4.测试结果
package com.eshang.aop.learning;
import com.eshang.aop.learning.controller.StudentController;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
@SpringBootTest
class AopLearningApplicationTests {
@Resource
StudentController studentController;
@Test
void contextLoads() {
studentController.testAop();
}
}
5.进阶内容:代码计时器
目标:用注解的形式实现代码计时器,对代码运行时间计时,并且可以在注解中自行定义计时单位
5.1.注解类Timing
package com.eshang.aop.learning.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author xyx-Eshang
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Timing {
String unit() default "ms";
}
5.2.切面类TimingAspect
package com.eshang.aop.learning.annotation;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
/**
* @author xyx-Eshang
*/
@Aspect
@Component
public class TimingAspect {
@Around("@annotation(timing)")
public Object timingAdvice(ProceedingJoinPoint pjp, Timing timing) throws Throwable {
try {
double beforeTime = System.currentTimeMillis();
Object result = pjp.proceed();
double consuming = System.currentTimeMillis() - beforeTime;
//根据单位,对显示的数值进行处理
if ("s".contentEquals(timing.unit())) {
consuming = consuming / 1000;
} else if("min".contentEquals(timing.unit())){
consuming = consuming / (1000 * 60);
} else if ("h".contentEquals(timing.unit())) {
consuming = consuming / (1000 * 60 * 60);
}
System.out.println("总用时为:" + consuming + timing.unit());
return result;
} catch (Exception e) {
System.out.println("发生异常,请检查AOP的代码!");
return null;
}
}
}
5.3.控制器StudentController
在testAop方法上使用@Timing(unit = “s”),括号内容表示以秒为单位
package com.eshang.aop.learning.controller;
import com.eshang.aop.learning.annotation.Eshang;
import com.eshang.aop.learning.annotation.Timing;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author xyx-Eshang
*/
@RestController
@RequestMapping("/student")
public class StudentController {
@Timing(unit = "s")
@PostMapping("/testAop")
public void testAop() {
System.out.println("现在执行testAop方法");
}
}
5.4.测试类AopLearningApplicationTests
package com.eshang.aop.learning;
import com.eshang.aop.learning.controller.StudentController;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
@SpringBootTest
class AopLearningApplicationTests {
@Resource
StudentController studentController;
@Test
void contextLoads() {
studentController.testAop();
}
}
5.5.测试结果