Spring Boot 自定义注解 + 拦截器
先看一个大家比较熟悉的东西,for example
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD,
ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
boolean required() default true;
}
嘿嘿,这是一个@Autowired注解源码。看下都有什么东西。
首先是三个注解:
- @Target
- @Retention
- @Documented
其次使用 @interface 定义这个类。
最后一个参数,required,我们可以这样使用: @Autowired(required = true)
一个一个解释:
@Target
看@Autowired源码中@Target后面跟了一大堆参数,里面有啥构造函数,方法,参数等等。我们猜一下,@Target注解,不就是告诉我们,你自定义的注解,可以在哪里使用麼。看下源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
/**
* Returns an array of the kinds of elements an annotation type
* can be applied to.
* @return an array of the kinds of elements an annotation type
* can be applied to
*/
ElementType[] value();
}
public enum ElementType {
/** 类,接口(包括注解类型)或枚举的声明 */
TYPE,
/** 属性的声明 */
FIELD,
/** 方法的声明 */
METHOD,
/** 参数的声明 */
PARAMETER,
/** 构造函数的声明 */
CONSTRUCTOR,
/** 局部变量的声明 */
LOCAL_VARIABLE,
/** 注解类型声明 */
ANNOTATION_TYPE,
/** 包的声明 */
PACKAGE,
/**
* 类型参数声明
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* 使用类型
*
* @since 1.8
*/
TYPE_USE
}
所以@Target就是告诉我们你自定义接口,在那里可以使用。
@Retention
这个看@Autowired中定义,参数有一个RUNTIME — 运行时间。那么这个参数是告诉我们在什么时候监控自定义参数的?老规则看下源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
public enum RetentionPolicy {
/**
* 注解将被编译器忽略掉.
*/
SOURCE,
/**
* 注解将被编译器记录在class文件中,但在运行时不会被虚拟机保留,这是一个默认的行为
*/
CLASS,
/**
* 注解将被编译器记录在class文件中,而且在运行时会被虚拟机保留,
* 因此它们能通过反射被读取到
*/
RUNTIME
}
再详解一下:
- 如果一个注解被定义为 - SOURCE,则它将被限定在Java源文件中,那么这个注解即不会参与编译也不会在运行期起任何作用,这个注解就和一个注释是一样的效果,只能被阅读Java文件的人看到;
- 如果一个注解被定义为RetentionPolicy.CLASS,则它将被编译到Class文件中,那么编译器可以在编译时根据注解做一些处理动作,但是运行时JVM(Java虚拟机)会忽略它,我们在运行期也不能读取到;
- 如果一个注解被定义为RetentionPolicy.RUNTIME,那么这个注解可以在运行期的加载阶段被加载到Class对象中。那么在程序运行阶段,我们可以通过反射得到这个注解,并通过判断是否有这个注解或这个注解中属性的值,从而执行不同的程序代码段。我们实际开发中的自定义注解几乎都是使用的RetentionPolicy.RUNTIME;
- 在默认的情况下,自定义注解是使用的RetentionPolicy.CLASS。
@Documented
说明该注解将被包含在javadoc中
@interface
@interface用来声明当前类是一个注解
自定义参数
既然是自定义参数,你可以取任何名字,当然大部分都是value,name等。你同时可以指定默认值,后面加上default。比如:WriteRandom xxxx() default xxxxxx;
ok,那么我们知道了怎么自定义一个注解,先写一个
自定义注解:CustomInterface
import java.lang.annotation.*;
@Documented
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomInterface {
/**
* RAND_ONE
*/
WriteRandom one() default WriteRandom.RAND_ONE;
/**
* num
*/
WriteRandom two() default WriteRandom.RAND_TWO;
}
@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public enum WriteRandom {
/**
* 第一
*/
RAND_ONE("ONE", 1),
/**
* 第二
*/
RAND_TWO("TWO", 2);
/**
* describe
*/
private String describe;
/**
* num
*/
private int num;
}
既然定义好了注解,那么怎么获取呢?这个篇文章的主题是自定义注解+拦截器,所以我们把获取注解的地方写在拦截器里面了。下面开始写拦截器。
Handler
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CustomInterfaceInterceptor extends HandlerInterceptorAdapter {
long start = System.currentTimeMillis();
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("Interceptor cost="+(System.currentTimeMillis()-start));
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
@Override
public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler) {
String result = buildLimitInfo(handler);
if (StringUtils.isEmpty(result)) {
System.out.println("---------------------");
} else {
System.out.println(result);
}
return true;
}
private String buildLimitInfo(Object handler) {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
CustomInterface rateLimiter = handlerMethod.getMethodAnnotation(CustomInterface.class);
String describe = rateLimiter.one().getDescribe();
int num = rateLimiter.two().getNum();
return "describe: " + describe + " num: " + num;
}
return null;
}
}
config
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Configuration
public class TestConfiguration extends WebMvcConfigurationSupport {
@Bean
public CustomInterfaceInterceptor customInterface() {
return new CustomInterfaceInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new CustomInterfaceInterceptor()).addPathPatterns("/**");
super.addInterceptors(registry);
}
}
最后我们写Controller
Controller
import com.study.test.testInterfance.CustomInterface;
import com.study.test.testInterfance.WriteRandom;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author shengda.ji
* @date 2019/4/15 12:03 PM
*/
@RestController
public class TestCustomInterface {
@CustomInterface(one = WriteRandom.RAND_ONE)
@GetMapping(value = "/testCustomInterface")
public String testCustomInterface() {
return "testCustomInterface--testCustomInterface";
}
}
还没有评论,来说两句吧...