注解
注解概念
什么是注解
注解用来给类声明附加额外信息,可以标注在类、字段、方法等上面,编译器、JVM以及开发人员等都可以通过反射拿到注解信息,进而做一些相关处理
SpringBoot 全部都是采用注解化
常用注解
@Override 只能标注在子类覆盖父类的方法上面,有提示的作用
@Deprecated 标注在过时的方法或类上面,有提示的作用
@SuppressWarnings("unchecked") 标注在编译器认为有问题的类、方法等上面,用来取消编译器的警告提示,警告类型有serial、unchecked、unused、all
元注解
元注解用来在声明新注解时指定新注解的一些特性
@Target 指定新注解标注的位置,比如类、字段、方法等,取值有ElementType.Method等
@Retention 指定新注解的信息保留到什么时候,取值有RetentionPolicy.RUNTIME等
@Inherited 指定新注解标注在父类上时可被子类继承
常用注解
@Target(ElementType.METHOD) // 指定新注解可以标注在方法上
@Retention(RetentionPolicy.RUNTIME) // 指定新注解保留到程序运行时期
@Inherited // 指定新注解标注在父类上时可被子类继承
public @interface MayiktName {
public String name();
}
自定义注解 运行 :反射+aop
注解的Target
TYPE:类、接口(包括注解类型)和枚举的声明
FIELD:字段声明(包括枚举常量)
METHOD:方法声明
PARAMETER:参数声明
CONSTRUCTOR:构造函数声明
LOCAL_VARIABLE:本地变量声明
ANNOTATION_TYPE:注解类型声明
PACKAGE:包声明
TYPE_PARAMETER:类型参数声明,JavaSE8引进,可以应用于类的泛型声明之处
TYPE_USE:JavaSE8引进,此类型包括类型声明和类型参数声明
获取注解信息
// 1.获取当前类上的注解 Class<?> aClass = Class.forName("com.mayikt.entity.UserEntity"); // MayiktName declaredAnnotation = aClass.getDeclaredAnnotation(MayiktName.class); // System.out.println(declaredAnnotation); // 2.获取当前方法上的注解 // Method userNameMethod = aClass.getDeclaredMethod("getUserName"); // MayiktName declaredAnnotation = userNameMethod.getDeclaredAnnotation(MayiktName.class); // System.out.println(declaredAnnotation); // 3.获取字段上的注解 Field pubUserName = aClass.getDeclaredField("pubUserName"); final MayiktName declaredAnnotation = pubUserName.getDeclaredAnnotation(MayiktName.class); System.out.println(declaredAnnotation);
// 4.获得构造方法注解
Constructor<TestAnnotation> constructors = clazz.getConstructor(new Class[] {});// 先获得构造方法对象
MyConstructorAnnotation myConstructorAnnotation = constructors.getAnnotation(MyConstructorAnnotation.class);// 拿到构造方法上面的注解实例
System.out.println(myConstructorAnnotation.desc() + "+" + myConstructorAnnotation.uri());
|
注解如何生效
实际项目中 注解想生效通过反射+aop机制
注解实现案例
自定义限流注解
对我们接口实现 限流 比如 每s 只能访问1次 或者每s 访问两次。
Maven
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.1.RELEASE</version> </parent> <dependencies> <!-- springboot 整合web组件--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>18.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.12.0</version> </dependency>
</dependencies>
|
使用谷歌的guava例子
/** * 每秒生成2.0个令牌 * // */ // private RateLimiter rateLimiter = RateLimiter.create(2.0); @GetMapping("/get") // @MayiktCurrentLimit(name = "get", token = 1) public String get() { // boolean result = rateLimiter.tryAcquire(); // if (!result) { // return "当前访问人数过多,请稍后重试!"; // } return "my is get"; }
|
封装自定义注解限流框架
整合自定义注解
整合Aop实现接口限流
package com.mayikt.service.aop;
import com.google.common.util.concurrent.RateLimiter; import com.mayikt.service.annotation.MayiktCurrentLimit; import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component;
import java.util.concurrent.ConcurrentHashMap;
/** * @author 余胜军 * @ClassName ExtTransactionalAop * @qq 644064779 * @addres www.mayikt.com * 微信:yushengjun644 */ @Aspect @Component public class CurrentLimitAop { /** * 每秒生成1.0个令牌 每s产生10 token */ // private RateLimiter rateLimiter = RateLimiter.create(1); private ConcurrentHashMap<String, RateLimiter> rateLimiters = new ConcurrentHashMap();
@Around(value = "@annotation(com.mayikt.service.annotation.MayiktCurrentLimit)") public Object around(ProceedingJoinPoint joinPoint) { try { //获取拦截的方法名 Signature sig = joinPoint.getSignature(); //获取拦截的方法名 MethodSignature methodSignature = (MethodSignature) sig; // 判断方法上是否有加上该注解,如果有加上注解则限流 MayiktCurrentLimit mayiktCurrentLimit = methodSignature.getMethod().getDeclaredAnnotation(MayiktCurrentLimit.class); if (mayiktCurrentLimit == null) { // 执行目标方法 return joinPoint.proceed(); } // 获取注解上的name String name = mayiktCurrentLimit.name(); // 获取注解上的token double token = mayiktCurrentLimit.token(); RateLimiter rateLimiter = rateLimiters.get(name); if (rateLimiter == null) { rateLimiter = RateLimiter.create(token); rateLimiters.put(name, rateLimiter); } // 开始限流 boolean result = rateLimiter.tryAcquire(); if (!result) { return "当前访问人数过多,请稍后重试!"; } return joinPoint.proceed(); } catch (Throwable throwable) { return "系统出现了错误!"; } } }
|
使用效果
package com.mayikt.service;
import com.google.common.util.concurrent.RateLimiter;
import com.mayikt.service.annotation.MayiktCurrentLimit;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 余胜军
* @ClassName MemberService
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@RestController
public class MemberService {
/**
* 每秒生成2.0个令牌
* //
*/
// private RateLimiter rateLimiter = RateLimiter.create(2.0);
@GetMapping("/get")
// @MayiktCurrentLimit(name = "get", token = 1)
public String get() {
// boolean result = rateLimiter.tryAcquire();
// if (!result) {
// return "当前访问人数过多,请稍后重试!";
// }
return "my is get";
}
@GetMapping("/add")
@MayiktCurrentLimit(name = "add", token = 5)
public String add() {
return "my is add";
}
@GetMapping("/my")
@MayiktCurrentLimit()
public String my() {
return "my is add";
}
}
|
http://127.0.0.1:8080/get
http://127.0.0.1:8080/my