使用@interface之前先了解注解

标准注解

@Override:表示当前的方法定义将覆盖超类中的方法。
@Deprecated:如果程序员使用了注解为它的元素,那么编译器会发出警告信息。
@SuppressWarnings:关闭不当的编译器警告信息。在java SE5之前的版本中,也可以使用该注解,不过会被忽略不起作用。

**

元注解

@Target 表示该注解用于什么地方,可能的值在枚举类 ElemenetType 中,包括:

ElemenetType.CONSTRUCTOR——————————————-构造器声明
ElemenetType.FIELD —————————————————域声明(包括 enum 实例)
ElemenetType.LOCAL_VARIABLE————————————- 局部变量声明
ElemenetType.METHOD ————————————————-方法声明
ElemenetType.PACKAGE ————————————————包声明
ElemenetType.PARAMETER ———————————————参数声明
ElemenetType.TYPE—————————————————- 类,接口(包括注解类型)或enum声明
@Retention 表示在什么级别保存该注解信息。可选的参数值在枚举类型 RetentionPolicy 中,包括:

RetentionPolicy.SOURCE——————-注解将被编译器丢弃
RetentionPolicy.CLASS ——————-注解在class文件中可用,但会被VM丢弃
RetentionPolicy.RUNTIME ————-VM将在运行期也保留注释,因此可以通过反射机制读取注解的信息。
@Documented 将此注解包含在 javadoc 中 ,它代表着此注解会被javadoc工具提取成文档。在doc文档中的内容会因为此注解的信息内容不同而不同。相当于@see,@param 等。
**
@Inherited 允许子类继承父类中的注解。

**

@interface

使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。

代码示例

1.创建自定义注解,我这里的自定义注解用于数据字典添加或更新时做一个Redis的同步数据更新。

  1. @Target(ElementType.METHOD)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. public @interface DictCacheManager {
  5. String desc();
  6. // 如果为true,需要使用response当做参数
  7. boolean isUseResponse() default false;
  8. }

2.添加自定义注解

  1. @RestController
  2. @RequestMapping("/v2/dictionary")
  3. public class DictionaryController {
  4. @DubboReference(check = true)
  5. private IV2DictionaryService IV2DictionaryService;
  6. @Autowired
  7. private DictCacheOperator dictCacheOperator;
  8. @PostMapping("/add")
  9. @DictCacheManager(desc = "新增字典")
  10. public ResponseData add(@RequestBody Dictionary dictionary) {
  11. return ResponseData.success(IV2DictionaryService.addDictionary(dictionary));
  12. }
  13. }

3.使用AOP拦截,并进行业务逻辑处理

  1. @Slf4j
  2. @Aspect
  3. @Component
  4. public class DictCacheManagerAspect {
  5. @Autowired
  6. private DictCacheOperator dictCacheOperator;
  7. //使用@annotation用于拦截@DictCacheManager注解
  8. @AfterReturning(value = "@annotation(producer)", returning = "response")
  9. public void doAfterReturning(JoinPoint joinPoint, ResponseData response, DictCacheManager producer) {
  10. log.info("send msg to redis start.");
  11. boolean isUseResponse = producer.isUseResponse();
  12. Object[] requestDataArr = joinPoint.getArgs();
  13. Object requestData = requestDataArr.length > 0 ? requestDataArr[0] : new Object();
  14. if (!ResponseData.DEFAULT_SUCCESS_CODE.equals(response.getCode())) {
  15. // 如果不是成功,直接返回
  16. return;
  17. }
  18. Object data = isUseResponse ? response.getData() : requestData;
  19. if (ToolUtil.isEmpty(data)) {
  20. return;
  21. }
  22. ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, 5, 0L, TimeUnit.MICROSECONDS, new ArrayBlockingQueue<>(5));
  23. threadPoolExecutor.execute(() -> dictCacheOperator.cache(data));
  24. }
  25. }

4.处理Redis业务逻辑

  1. @Component
  2. @Slf4j
  3. public class DictCacheOperator {
  4. @Autowired
  5. private RedisService redisService;
  6. @DubboReference(check = true)
  7. private IV2DictionaryService dictionaryService;
  8. public void cache(Object data) {
  9. // 添加或修改字典
  10. if (data instanceof Dictionary) {
  11. Dictionary dictionary = (Dictionary) data;
  12. Dictionary queryDict = dictionaryService.queryDictionaryByCode(dictionary.getCode());
  13. DictItem dictItem = buildDictItem(dictionary);
  14. redisService.set(DICT_CACHE_KEY.concat(queryDict.getCode()), dictItem);
  15. }
  16. // 删除字典
  17. if (data instanceof List) {
  18. List<String> deleteCodes = CommonUtil.castList(data, String.class);
  19. deleteCodes.forEach(code -> {
  20. if (redisService.hasKey(DICT_CACHE_KEY.concat(code))) {
  21. redisService.del(DICT_CACHE_KEY.concat(code));
  22. }
  23. });
  24. }
  25. }
  26. }