Java中常见注解
三种标准注解:
-
@Override 表示重写父类(又叫超类)的方法(注意和重载的区别,重载方法参数个数不一样)
-
@Deprecated 表示已经过时,编译时会显示提示信息
-
@SuppressWarnings 关闭不当的编译器报警信息
常见第三方注解:
Spring: @Autowired @Service @Repository
Mybatis:@InsertProvider @UpdateProvider @Options
四种元注解:
- @Target({ElementType.METHOD, ElementType. TYPE})
- @Retention(RetentionPo
- @lnherited
- @Documented
public @interface Description {
String desc();
String author();
int age() default 18;
}
自定义注解语法要求:
- 使用@interface关键字自定义注解
- 成员以无参无异常方式声明
- 成员类型是受限的,合法的类型包括原始类型及String, Class, Annotation(注释), Enumeration(枚举)
- 可以用default为成员指定一个默认值
- 如果注解只有一个成员,则成员名必须取名为value(),在使用时可省略 成员名=
- 注解类可以没有成员,没有成员的注解为标识注解
四个元注解的作用:(元注解就是注解的注解)
1、 @Target 表示该注解的作用范围,可能的值在枚举类 ElemenetType 中,包括:
-
ElemenetType.CONSTRUCTOR 构造器(构造方法)声明
-
ElemenetType.FIELD 域(字段)声明(包括 enum 实例)
-
ElemenetType.LOCAL_VARIABLE 局部变量声明
-
ElemenetType.METHOD 方法声明
-
ElemenetType.PACKAGE 包声明
-
ElemenetType.PARAMETER 参数声明
-
ElemenetType.TYPE 类,接口(包括注解类型)或enum声明
2、@Retention 表示该注解的生命周期。可选的参数值在枚举类型 RetentionPolicy 中,包括:
-
RetentionPolicy.SOURCE 注解将被编译器丢弃,只在源码显示
-
RetentionPolicy.CLASS 注解在class文件中可用,但会被VM丢弃(运行时)
-
RetentionPolicy.RUNTIME VM将在运行期也保留注释,因此可以通过反射机制读取注解的信息。
3、@Inherited 允许子类继承父类中的注解。
@Documented 将此注解包含在 javadoc 中 ,它代表着此注解会被javadoc工具提取成文档。在doc文档中的内容会因为此注解的信息内容不同而不同。相当与@see,@param 等。(可使用Export -> Javadoc方式生成Javadoc)
4、@Order(Ordered.HIGHEST_PRECEDENCE) 注解优先级
自定义注解的使用:
语法: @注解名(成员名1 = 成员值1, 成员名2 = 成员值2, …)
@Description(desc="I am eyeColor", author="Wayne Chu", age=18)
public String eyeColor(){
rerurn "red";
}
示例:注解的解析
通过反射机制获取注解的信息
public class ParseAnn {
public static void main(String\[\] args) {
try {
// 使用类加载器加载类
Class c = Class.forName("cn.waynechu.Persion");
// 找到类上面的注解
boolean isExist = c.isAnnotationPresent(Description.class);
// 上面的这个方法是用这个类来判断这个类是否存在Description这样的一个注解
if (isExist) {
// 拿到注解实例,解析类上面的注解
Description d = (Description) c.getAnnotation(Description.class);
System.out.println(d.value());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
示例: repository注解的定义
@Target({ElementType.TYPE})
// 表示作用范围为类、接口或enum声明
@Retention(RetentionPolicy.RUNTIME)
// 表示生命周期为运行期间,可通过反射机制读取注解信息,或者通过AOP拿到
@Documented
@Component
public @interface Repository{
/\*\*
\*Thevaluemayindicateasuggestionforalogicalcomponentname,
\*tobeturnedintoaSpringbeanincaseofanautodetectedcomponent.
\*@return thesuggestedcomponentname,ifany
\*/
String value() default"";
}
示例:自定义用于IP访问控制注解
/\*\*
\* 用于IP访问控制
\* 可添加黑名单、白名单策略
\*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Order(Ordered.HIGHEST\_PRECEDENCE)
public @interface LimitIPRequest {
/\*\*
\* 限制某时间段内可访问次数,默认5次
\*/
int limitCounts() default 5;
/\*\*
\* 限制访问的间段,默认为60秒
\*/
int timeSecond() default 60;
/\*\*
\* IP白名单,跳过访问次数检查
\*/
String\[\] whiteList() default {"172.17.0.1"};
/\*\*
\* IP黑名单,无接口访问权限
\*/
String\[\] blackList() default {};
}
通过AspectJ切面JoinPoint获取方法签名->获取注解及信息
@Aspect
@Component
public class LimitIPRequestAspect {
private static final Logger logger = LoggerFactory.getLogger(LimitIPRequestAspect.class);
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Pointcut("execution(\* com.fintech.intellinews.web.\*.\*(..)) && @annotation(com.fintech.intellinews.annotation.LimitIPRequest)")
public void before() {
}
@Before("before()")
public void requestLimit(JoinPoint joinPoint) {
// 获取HttpRequest
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
LimitIPRequest limitIPRequest = getAnnotation(joinPoint);
if (limitIPRequest == null) {
return;
}
String ip = request.getRemoteAddr();
String uri = request.getRequestURI().toLowerCase();
// 黑名单检测
for (String whiteIP : limitIPRequest.blackList()) {
if (whiteIP.equals(ip)) {
logger.debug("【BLACK\_IP\_REQUEST】,url{},ip{}", uri, ip);
throw new AppException(ResultEnum.BLACK\_IP\_REQUEST\_ERROR);
}
}
// 白名单检测
for (String whiteIP : limitIPRequest.whiteList()) {
if (whiteIP.equals(ip)) {
return;
}
}
String redisKey = "ip-request-count:" + uri + ":" + ip;
// 在redis自增,步长为1
long count = redisTemplate.opsForValue().increment(redisKey, 1);
// 从第一次访问开始计时
if (count == 1) {
redisTemplate.expire(redisKey, limitIPRequest.timeSecond(), TimeUnit.SECONDS);
}
if (count > limitIPRequest.limitCounts()) {
logger.debug("【FREQUENTLY\_IP\_REQUEST】,url{},ip{}", uri, ip);
throw new AppException(ResultEnum.FREQUENTLY\_IP\_REQUEST\_ERROR);
}
}
/\*\*
\* 获得注解
\*
\* @param joinPoint 切入点
\* @return 注解
\*/
private LimitIPRequest getAnnotation(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method != null) {
return method.getAnnotation(LimitIPRequest.class);
}
return null;
}
}