本文簡單說明一下元注解,然后對元注解中的@Retention做深入的討論,在文章最后使用元注解寫一個自定義注解來結尾。
一、結論:
@Target:注解的作用目標
@Target(ElementType.TYPE)——接口、類、枚舉、注解
@Target(ElementType.FIELD)——字段、枚舉的常量
@Target(ElementType.METHOD)——方法
@Target(ElementType.PARAMETER)——方法參數
@Target(ElementType.CONSTRUCTOR) ——構造函數
@Target(ElementType.LOCAL_VARIABLE)——局部變量
@Target(ElementType.ANNOTATION_TYPE)——注解
@Target(ElementType.PACKAGE)——包
@Retention:注解的保留位置
RetentionPolicy.SOURCE:這種類型的Annotations只在源代碼級別保留,編譯時就會被忽略,在class字節碼文件中不包含。
RetentionPolicy.CLASS:這種類型的Annotations編譯時被保留,默認的保留策略,在class文件中存在,但JVM將會忽略,運行時無法獲得。
RetentionPolicy.RUNTIME:這種類型的Annotations將被JVM保留,所以他們能在運行時被JVM或其他使用反射機制的代碼所讀取和使用。
@Document:說明該注解將被包含在javadoc中
@Inherited:說明子類可以繼承父類中的該注解
二、場景與樣例
此處對@Retention做特殊說明。
RetentionPolicy.SOURCE,編譯后的class文件不包含@Retention注釋,使用在編譯階段,主要是在編譯時做一些操作,例如:@Override和@SuppressWarnings(@Override:改注解向編譯器說明被注解元素是重寫的父類的一個元素。在重寫父類元素的時候此注解並非強制性的,不過可以在重寫錯誤時幫助編譯器產生錯誤以提醒我們。比如子類方法的參數和父類不匹配,或返回值類型不同;編譯通過后,方法上不再有@Override注解;@SuppressWarnings:在編譯時抑制編譯報錯)。
RetentionPolicy.CLASS,編譯后在class文件中仍然存在,但是運行時不會被JVM調用,即使是使用反射也不無法調用該注解,但是要是具體說他與RetentionPolicy.SOURCE的區別,除了是否會存在於class文件上之外,還沒有找到實質性的區別(很有可能的區別是:RetentionPolicy.SOURCE僅僅是給應用層開發人員用的,RetentionPolicy.CLASS 需要應用層和底層系統開發人員配合使用的,所以僅僅是應用層開發的我們是一臉懵逼)
三、自定義注解(以自定義日期校驗注解為例)
1、自定義注解
package com.example.demo.utils; import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.FIELD,ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = DateTimeValidator.class) public @interface DateTime { String message() default "格式錯誤"; String format() default "YYYY-MM-DD"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
其中@Constraint必須添加,改注解指定自定義注解的具體實現類。
2、自定義注解實現類(校驗邏輯實現類)
package com.example.demo.utils; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; import java.text.ParseException; import java.text.SimpleDateFormat; public class DateTimeValidator implements ConstraintValidator<DateTime, String> { private DateTime dateTime; @Override public void initialize(DateTime constraintAnnotation) { this.dateTime = constraintAnnotation; } @Override public boolean isValid(String value, ConstraintValidatorContext context) { if(context == null){ return true; } String format = dateTime.format(); if (value.length() != format.length()) { return false; } SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format); try { simpleDateFormat.parse(value); } catch (ParseException e) { return false; } return true; } }
3、自定義注解使用
@Validated @Controller @RequestMapping("/test") @Api(value = "SpringBoot測試接口2") public class UserTestController2 { @ResponseBody @PostMapping(value ="/validated2") @ApiOperation(value="validated表單驗證測試") @ApiImplicitParams( {@ApiImplicitParam(paramType="query", name = "date", value = "日期", dataType = "String")}) public String validated2(@DateTime(message = "格式錯誤啦啦啦啦",format = "yyyy-mm-dd") String date){ return "OK"; } @ResponseBody @PostMapping(value ="/validated3") @ApiOperation(value="validated表單驗證測試") @ApiImplicitParams( {@ApiImplicitParam(paramType="query", name = "date", value = "日期", dataType = "String")}) public String validated3(@DateTime String date){ return "OK"; } }
4、驗證