注解(Annotation)和自定义注解

1,408 阅读3分钟

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;

 }

}