一、注解的定义
java注解可以理解为一种的程序特性的标注,该标注代表某一种功能,可在运行时反射来动态实现功能映射,也有作用于源码和字节码的。其中,用来标记自定义注解的称为元注解
(meta-annotation),有Target、Retention、Documented和Inherited。
二、元注解
元注解是用于修饰其它注解的注解。 JDK5.0提供了四种元注解:Retention, Target, Documented, Inherited
1、@Retention:用于指定修饰的注解的生命周期,@Rentention包含一个RetentionPolicy枚举类型的成员变量,使用@Rentention时必须为该value成员变量指定值:
SOURCE:只在源文件中有效,编译器直接丢弃这种策略的注释,在.class文件中不会保留注解信息。反编译查看字节码文件:发现字节码文件中没有MyAnnotation这个注解
CLASS: 在class文件中有效,保留在.class文件中,但是当运行Java程序时,不会继续加载了,不会保留在内存中,JVM不会保留注解。
如果注解没有加Retention元注解,那么相当于默认的注解就是这种状态。
RUNTIME:在运行时有效(即运行时保留),当运行 Java程序时,JVM会保留注释,加载在内存中了,那么程序可以通过反射获取该注释。
2、@Target:用于修饰注解的注解,用于指定被修饰的注解能用于修饰哪些程序元素,即修饰位置。@Target也包含一个名为value的成员变量。
3、@Documented:用于指定被该元注解修饰的注解类将被javadoc工具提取成文档。默认情况下,javadoc是 不包括注解的,但是加上了这个注解生成的文档中就会带着注解了
4、@Inherited: 被它修饰的Annotation将具有继承性。如果某个类使用了被 @Inherited修饰的Annotation,则其子类将自动具有该注解。
三、注解属性定义
注解属性 ( 接口方法 ) 返回值类型要求 :
基本数据类型 : byte , short , int , long , float , double , char , boolean ;
字符串类型 : String ;
枚举类型 : enum ;
注解类型 ;
以上类型的数组形式 ;
可以使用default来进行赋默认值
案例:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AdminLoginToken {
@AliasFor("admin")
boolean value() default true;
@AliasFor("value")
boolean admin() default true;
}
四、使用案例演示
模拟是否需要进行登录校验;如果方法中加上了@LoginRequired注解表示方法需要登录校验,如果没加则不需要。定义一个
@LoginRequired注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public@interface LoginRequired {
}
定义两个简单接口,其中一个添加@LoginRequired注解表示需要登录校验
@RestController
public class UserController {
@GetMapping("/login1")
public TransDTO login1(){
return new TransDTO<>().withMessage("访问login1成功").withCode(HttpStatus.OK.value());
}
@LoginRequired
@GetMapping("/login2")
public TransDTO login2(){
return new TransDTO<>().withMessage("访问login2成功").withCode(HttpStatus.OK.value());
}
}
自定义拦截器
@Configuration
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("访问了过滤器!");
HandlerMethod handlerMethod = (HandlerMethod) handler;
LoginRequired annotation = handlerMethod.getMethod().getAnnotation(LoginRequired.class);
if(annotation != null){
//全局异常处理会进行处理
throw new BusinessException("访问失败,您没有权限访问!");
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
配置拦截路径
@Configuration
public class InterceptorTrainConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
}
}
全局异常处理
@RestControllerAdvice
public class MyExceptionAdvice {
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.OK)
public TransDTO handleException(HttpServletRequest request,Exception e){
e.printStackTrace();
return new TransDTO().withCode(500).withSuccess(false).withMessage(e.getMessage());
}
}
五、总结
自定义注解的场景有很多,比如登录、权限拦截、日志、以及各种框架。java注解对于性能有较大的影响,但可用于软件的架构设计,实现动态加载,对于分解复杂业务有帮助。