注解
1.1 什么是注解
- 注解用來給類宣告附加額外資訊,可以標注在類、欄位、方法上面,編譯器、JVM以及代碼中可以通過反射獲取注解資訊,進行做處理
- 比如控制層主要方法添加的日志注解,可以通過日志注解中獲取資訊,然后保存記錄日志資料,方便代碼的除錯
1.2 常用注解
- @Override
- 標注在子類重寫的父類方法之上,具有提示作用
- @Deprecated
- 標注該類或者方法已過時,在后續版本中會被遺棄,具有提示作用
- @SuppressWarning(“unchecked”)
- 標注在編譯器檢測到有問題的類、方法等上面,用來取消編譯器的警告提示,警告型別有serial、unchecked、unuserd、all
1.3 元注解
- 用來在宣告新的注解時,指定新注解的一些特性
- @Target:指定注解標注的位置,比如類、欄位、方法等

- TYPE:類、介面(包括注解)或者列舉宣告
- FIELD:欄位宣告(包括列舉常量)
- PARAMETER:引數宣告
- CONSTRUCTOR:建構式宣告
- LOCAL_VARIABLE:本地變數宣告
- ANNOTATION_TYPE:注解型別宣告
- PACKAGE:包宣告
- TYPE_PARAMETER:型別引數宣告,java8引入,可以用于類的泛型宣告的地方
- TYPE_USE:java8引入,此型別包括型別宣告和型別引數宣告
- @Retention:指定注解的資訊保留到什么時候
- @Inherited:指定注解標注在父類上時,可以被子類繼承
- @Documented:指定注解將被javadoc記錄
1.4 獲取注解資訊
-
幾個注解
-
類
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface ClassAnnotation { } -
建構式
@Target(ElementType.CONSTRUCTOR) @Retention(RetentionPolicy.RUNTIME) public @interface ConstructorAnnotation { } -
屬性
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface FieldAnnotation { } -
方法
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface MethodAnnotation { }
-
-
測驗類
@ClassAnnotation public class Test { @FieldAnnotation private String name; @MethodAnnotation public void test() { System.out.println("test()"); } @ConstructorAnnotation public Test() { } } -
測驗代碼
public class GetAnnotationMessage { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException { // 獲取class物件 Class<?> clazz = Class.forName("com.fc.reflectionandannotation.annotation.message.Test"); // 獲取類上面的注解資訊 Annotation[] classAnnotation = clazz.getDeclaredAnnotations(); Arrays.stream(classAnnotation).forEach(item -> { System.out.println(item); }); // 獲取欄位上的注解資訊 Field field = clazz.getDeclaredField("name"); Annotation[] fieldAnnotation = field.getDeclaredAnnotations(); Arrays.stream(fieldAnnotation).forEach(item -> { System.out.println(item); }); // 獲取方法上的注解資訊 Method method = clazz.getDeclaredMethod("test", null); Annotation[] methodAnnotation = method.getDeclaredAnnotations(); Arrays.stream(methodAnnotation).forEach(item -> { System.out.println(item); }); // 獲取構造方法上的注解資訊 Constructor<?> constructor = clazz.getDeclaredConstructor(null); Annotation[] declaredAnnotations = constructor.getDeclaredAnnotations(); Arrays.stream(declaredAnnotations).forEach(item -> { System.out.println(item); }); } }
1.5 注解如何生效
- 實際專案中 注解想生效通過反射+aop機制
1.6 限流注解
1.6.1 第三方api
-
使用google/guava實作
-
引入pom.xml依賴
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>fclever</artifactId> <groupId>com.fcleverframework</groupId> <version>0.0.1-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>fclever-reflection-annotation</artifactId> <description>Reflection and annotation Project</description> <dependencies> <!--SpringBoot整合Web插件--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--aop切面--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <!--guava--> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>18.0</version> </dependency> <!--常用工具類包--> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.12.0</version> </dependency> </dependencies> </project> -
搭建SpringBoot專案,通過控制層控制
/** * @ClassName LimitController * @Description 限流控制層 * @Author Fclever * @Date 2021/9/13 18:15 **/ @RestController public class LimitController { /** * 每秒產生2個令牌,一秒內只能訪問該介面兩次 */ private RateLimiter rateLimiter = RateLimiter.create(1.0); @GetMapping("/get") public String get() { // 判斷是否可訪問,true可 false不可 boolean result = rateLimiter.tryAcquire(); if (!result) { return "訪問人數過多,請稍后重試!"; } return "Fclever"; } }
1.6.2 封裝自定義限流注解
-
思路
- 限流注解
- AOP環繞通知
- 反射判斷方法時候含有注解
- 獲取注解資訊,支撐不同方法對限流規則的需求
-
需要考慮的問題,使用該注解的方法可能所需的限流規則不一樣,因此可以在注解中增設引數,支撐不用情景下的使用,
-
代碼
/** * @ClassName FcleverCurrentLimit * @Description 自定義的限流注解 * @Author Fclever * @Date 2021/9/22 16:14 **/ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface CurrentLimit { /** * 進行限流的方法名稱 * * @return */ String name() default ""; /** * 該方法每秒能被訪問的次數限制 * 底層:令牌桶演算法 * @return */ int token() default 10; } -
限流注解如何生效?注解已經撰寫完畢,直接在方法上是無法生效的,這時候需要借助AOP實作,Spring的AOP含有多種型別的通知,可以實作在方法前后等做處理攔截,
1.6.3 整合AOP實作限流
-
補充知識:
- 環繞通知中存在可以對目標方法進行呼叫,實作靈活的操作目標方法的執行情況,方法的回傳值為目標方法的回傳值,
- 前置和后置無法直接控制呼叫目標方法,
- 前置、后置、環繞同時存在,如果環繞不呼叫目標方法,則前置和后置失效,
- 多種通知的執行順序
- 目標方法無例外
- @Around
- @Before
- @AfterReturning
- @After
- @Around
- 目標方法有例外
- @Around
- @Before
- @AfterThrowing
- @After
- 目標方法無例外
-
AOP代碼
/** * @ClassName CurrentLimitAop * @Description * @Author Fclever * @Date 2021/9/22 16:24 **/ @Aspect @Component public class CurrentLimitAop { // 存放不同方法上的含有限流注解的限流規則物件 private ConcurrentHashMap<String, RateLimiter> rateLimiters = new ConcurrentHashMap<>(); /** * 環繞通知 * 只要在方法上添加了該限流注解,就可以被AOP的環繞通知攔截 * 1. 通過反射判斷方法上時候含有【限流注解】 * 2. 若存在,獲取限流注解中的【token】值,使用guava創建對應的RateLimiter,呼叫限流api */ @Around(value = "@annotation(com.fc.reflectionandannotation.currentLimiting.annotation.CurrentLimit)") public Object around(ProceedingJoinPoint proceedingJoinPoint) { try { // 獲取方法 Signature signature = proceedingJoinPoint.getSignature(); MethodSignature methodSignature = (MethodSignature) signature; // 獲取方法上的指定注解,這里不要判斷是否該方法上存在該注解,因為已經進入了環繞通知,肯定是存在注解的 // 這里主要關注的是獲取注解當中的資訊 CurrentLimit currentLimit = methodSignature.getMethod().getDeclaredAnnotation(CurrentLimit.class); String name = currentLimit.name(); int token = currentLimit.token(); RateLimiter rateLimiter = null; if(rateLimiters.containsKey(name)) { rateLimiter = rateLimiters.get(name); } else { rateLimiter = RateLimiter.create(token); rateLimiters.put(name, rateLimiter); } if(!rateLimiter.tryAcquire()){ return "當前訪問人數過多!"; } // 回傳值為目標方法回傳值 Object result = proceedingJoinPoint.proceed(); return result; } catch (Throwable throwable) { return "方法報錯"; } } } -
控制層代碼
-

} // 回傳值為目標方法回傳值 Object result = proceedingJoinPoint.proceed(); return result; } catch (Throwable throwable) { return "方法報錯"; }}
}
-
-
控制層代碼
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/387068.html
標籤:其他
下一篇:MyBatis原來做的是這些事


