Spring Boot 自定义注解 + 拦截器

逃离我推掉我的手 2022-02-19 04:59 632阅读 0赞

先看一个大家比较熟悉的东西,for example

  1. @Target({ElementType.CONSTRUCTOR, ElementType.METHOD,
  2. ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
  3. @Retention(RetentionPolicy.RUNTIME)
  4. @Documented
  5. public @interface Autowired {
  6. boolean required() default true;
  7. }

嘿嘿,这是一个@Autowired注解源码。看下都有什么东西。
首先是三个注解:

  1. @Target
  2. @Retention
  3. @Documented
    其次使用 @interface 定义这个类。
    最后一个参数,required,我们可以这样使用: @Autowired(required = true)

一个一个解释:

@Target

看@Autowired源码中@Target后面跟了一大堆参数,里面有啥构造函数,方法,参数等等。我们猜一下,@Target注解,不就是告诉我们,你自定义的注解,可以在哪里使用麼。看下源码:

  1. @Documented
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Target(ElementType.ANNOTATION_TYPE)
  4. public @interface Target {
  5. /**
  6. * Returns an array of the kinds of elements an annotation type
  7. * can be applied to.
  8. * @return an array of the kinds of elements an annotation type
  9. * can be applied to
  10. */
  11. ElementType[] value();
  12. }
  13. public enum ElementType {
  14. /** 类,接口(包括注解类型)或枚举的声明 */
  15. TYPE,
  16. /** 属性的声明 */
  17. FIELD,
  18. /** 方法的声明 */
  19. METHOD,
  20. /** 参数的声明 */
  21. PARAMETER,
  22. /** 构造函数的声明 */
  23. CONSTRUCTOR,
  24. /** 局部变量的声明 */
  25. LOCAL_VARIABLE,
  26. /** 注解类型声明 */
  27. ANNOTATION_TYPE,
  28. /** 包的声明 */
  29. PACKAGE,
  30. /**
  31. * 类型参数声明
  32. *
  33. * @since 1.8
  34. */
  35. TYPE_PARAMETER,
  36. /**
  37. * 使用类型
  38. *
  39. * @since 1.8
  40. */
  41. TYPE_USE
  42. }

所以@Target就是告诉我们你自定义接口,在那里可以使用。

@Retention

这个看@Autowired中定义,参数有一个RUNTIME — 运行时间。那么这个参数是告诉我们在什么时候监控自定义参数的?老规则看下源码:

  1. @Documented
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Target(ElementType.ANNOTATION_TYPE)
  4. public @interface Retention {
  5. /**
  6. * Returns the retention policy.
  7. * @return the retention policy
  8. */
  9. RetentionPolicy value();
  10. }
  11. public enum RetentionPolicy {
  12. /**
  13. * 注解将被编译器忽略掉.
  14. */
  15. SOURCE,
  16. /**
  17. * 注解将被编译器记录在class文件中,但在运行时不会被虚拟机保留,这是一个默认的行为
  18. */
  19. CLASS,
  20. /**
  21. * 注解将被编译器记录在class文件中,而且在运行时会被虚拟机保留,
  22. * 因此它们能通过反射被读取到
  23. */
  24. RUNTIME
  25. }

再详解一下:

  1. 如果一个注解被定义为 - SOURCE,则它将被限定在Java源文件中,那么这个注解即不会参与编译也不会在运行期起任何作用,这个注解就和一个注释是一样的效果,只能被阅读Java文件的人看到;
  2. 如果一个注解被定义为RetentionPolicy.CLASS,则它将被编译到Class文件中,那么编译器可以在编译时根据注解做一些处理动作,但是运行时JVM(Java虚拟机)会忽略它,我们在运行期也不能读取到;
  3. 如果一个注解被定义为RetentionPolicy.RUNTIME,那么这个注解可以在运行期的加载阶段被加载到Class对象中。那么在程序运行阶段,我们可以通过反射得到这个注解,并通过判断是否有这个注解或这个注解中属性的值,从而执行不同的程序代码段。我们实际开发中的自定义注解几乎都是使用的RetentionPolicy.RUNTIME;
  4. 在默认的情况下,自定义注解是使用的RetentionPolicy.CLASS。

@Documented

说明该注解将被包含在javadoc中

@interface

@interface用来声明当前类是一个注解

自定义参数

既然是自定义参数,你可以取任何名字,当然大部分都是value,name等。你同时可以指定默认值,后面加上default。比如:WriteRandom xxxx() default xxxxxx;

ok,那么我们知道了怎么自定义一个注解,先写一个

自定义注解:CustomInterface

  1. import java.lang.annotation.*;
  2. @Documented
  3. @Target({ElementType.TYPE, ElementType.METHOD})
  4. @Retention(RetentionPolicy.RUNTIME)
  5. public @interface CustomInterface {
  6. /**
  7. * RAND_ONE
  8. */
  9. WriteRandom one() default WriteRandom.RAND_ONE;
  10. /**
  11. * num
  12. */
  13. WriteRandom two() default WriteRandom.RAND_TWO;
  14. }
  15. @Getter
  16. @AllArgsConstructor(access = AccessLevel.PRIVATE)
  17. public enum WriteRandom {
  18. /**
  19. * 第一
  20. */
  21. RAND_ONE("ONE", 1),
  22. /**
  23. * 第二
  24. */
  25. RAND_TWO("TWO", 2);
  26. /**
  27. * describe
  28. */
  29. private String describe;
  30. /**
  31. * num
  32. */
  33. private int num;
  34. }

既然定义好了注解,那么怎么获取呢?这个篇文章的主题是自定义注解+拦截器,所以我们把获取注解的地方写在拦截器里面了。下面开始写拦截器。

Handler

  1. import org.springframework.util.StringUtils;
  2. import org.springframework.web.method.HandlerMethod;
  3. import org.springframework.web.servlet.ModelAndView;
  4. import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
  5. import javax.servlet.http.HttpServletRequest;
  6. import javax.servlet.http.HttpServletResponse;
  7. public class CustomInterfaceInterceptor extends HandlerInterceptorAdapter {
  8. long start = System.currentTimeMillis();
  9. @Override
  10. public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
  11. System.out.println("Interceptor cost="+(System.currentTimeMillis()-start));
  12. }
  13. @Override
  14. public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
  15. }
  16. @Override
  17. public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler) {
  18. String result = buildLimitInfo(handler);
  19. if (StringUtils.isEmpty(result)) {
  20. System.out.println("---------------------");
  21. } else {
  22. System.out.println(result);
  23. }
  24. return true;
  25. }
  26. private String buildLimitInfo(Object handler) {
  27. if (handler instanceof HandlerMethod) {
  28. HandlerMethod handlerMethod = (HandlerMethod) handler;
  29. CustomInterface rateLimiter = handlerMethod.getMethodAnnotation(CustomInterface.class);
  30. String describe = rateLimiter.one().getDescribe();
  31. int num = rateLimiter.two().getNum();
  32. return "describe: " + describe + " num: " + num;
  33. }
  34. return null;
  35. }
  36. }

config

  1. import org.springframework.context.annotation.Bean;
  2. import org.springframework.context.annotation.Configuration;
  3. import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
  4. import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
  5. @Configuration
  6. public class TestConfiguration extends WebMvcConfigurationSupport {
  7. @Bean
  8. public CustomInterfaceInterceptor customInterface() {
  9. return new CustomInterfaceInterceptor();
  10. }
  11. @Override
  12. public void addInterceptors(InterceptorRegistry registry) {
  13. registry.addInterceptor(new CustomInterfaceInterceptor()).addPathPatterns("/**");
  14. super.addInterceptors(registry);
  15. }
  16. }

最后我们写Controller

Controller

  1. import com.study.test.testInterfance.CustomInterface;
  2. import com.study.test.testInterfance.WriteRandom;
  3. import org.springframework.web.bind.annotation.GetMapping;
  4. import org.springframework.web.bind.annotation.RestController;
  5. /**
  6. * @author shengda.ji
  7. * @date 2019/4/15 12:03 PM
  8. */
  9. @RestController
  10. public class TestCustomInterface {
  11. @CustomInterface(one = WriteRandom.RAND_ONE)
  12. @GetMapping(value = "/testCustomInterface")
  13. public String testCustomInterface() {
  14. return "testCustomInterface--testCustomInterface";
  15. }
  16. }

测试

网页
代码

发表评论

表情:
评论列表 (有 0 条评论,632人围观)

还没有评论,来说两句吧...

相关阅读