1-优质博客
2. 注解概述
- Annotation是从JDK5.0开始引入的新技术,注解有检查和约束的作用
- Annotation的作用:
- 不是程序本身,可以对程序作出解释。(这一点和注释(comment)没什么区别)
- 可以被其他程序(比如:编译器等)读取
- Annotation的格式:
- 注解是以”@注释名”在代码中存在的,还可以添加一些参数值,例如:@Suppress Warnings(value=”unchecked”).
- Annotation在哪里使用?
| 注解名称 | 作用 | 值 |
|---|---|---|
| @Target | 用于描述注解的使用范围(即:被描述的注解可以用在什么地方 | ElementType.TYPE:类、接口、注解、枚举 ElementType.FIELD:字段、枚举常量 ElementType.METHOD:方法 ElementType.PARAMETER:形式参数 ElementType.CONSTRUCTOR:构造方法 ElementType.LOCAL_VARIABLE:局部变量 ElementType.ANNOTATION_TYPE:注解 ElementType.PACKAGE:包 ElementType.TYPE_PARAMETER:类型参数 ElementType.TYPE_USE:类型使用 |
| @Retention | 表示需要在什么级别保存该注释信息,用于描述注解的生命周期 | RetentionPolicy.SOURCE:注解只保留在源码中,在编译时会被编译器丢弃 RetentionPolicy.CLASS:(默认的保留策略) 注解会被保留在Class文件中,但不 会被加载到虚拟机中,运行时无法获得 RetentionPolicy.RUNTIME:注解会被保留在Class文件中,且会被加载到虚拟机中,可以在运行时获得 [ |
](https://blog.csdn.net/Goodbye_Youth/article/details/84314928) |
| @Documented | 说明该注解将被包含在javadoc中 | 用于将注解包含在javadoc中
默认情况下,javadoc是不包括注解的,但如果使用了@Documented注解,则相关注解类型信息会被包含在生成的文档中 |
| @Inherited | 说明子类可以继承父类中的该注解 |
|
| @Repeatable | 用于声明标记的注解为可重复类型注解,可以在同一个地方多次使用 |
|
4. 内置注解
- @Override:定义在java.lang.Override中,此注解只适用于修辞方法,表示一个方法声明打算重写超类中的另一种方法声明
- @Deprecated:定义在java.lang.Deprecated中,此注释可以用于修辞方法,属性,类,表示不鼓励程序员使用这样的元素,通常是因为它很危险或者存在更好的选择
@SuppressWarnings:定义在java.lang.SuppressWarnings中,用来抑制编译时的警告信息。
- 与前两个注释有所不同,你需要添加一个参数才能正确使用,这些参数都是已经定义好了的,我们选择性使用就好了。
- @SuppressWarnings(“all”)
- @SuppressWarnings(“unchecked”)
- @SuppressWarnings(“value={“unchecked”,”deprecation”}”)
- 等等
- 平时写代码不建议镇压所有警告,因为警告可以帮我们识别错误
5. 自定义注解
使用@interface定义注解时,自动继承了java.lang.annotation.Annotation接口,
一般使用场景为:自定义注解+拦截器或者AOP,使用自定义注解来自己设计框架,使得代码看起来非常优雅。5.1 特性:
@interface用来声明一个注解,格式:public @interface 注解名{定义内容}
- 其中的每一个方法实际上是声明了一个配置参数,方法的名称就是参数的名称
- 返回值类型就是参数的类型(返回值只能是基本类型Class,String,enum)
- 可以通过default声明参数的默认值,如果只有一个参数成员,一般参数名为value
- 注解元素必须要有值,我们定义注解元素时,经常使用空字符串,0作为默认值
注解只有一个值,我们可以定义为Value,使用时Value可以省略不写,只有Value可以省略
5.2 使用(自定义注解+拦截器或者AOP):
@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface MyField {String description();int length();}
public class MyFieldTest {//使用我们的自定义注解@MyField(description = "用户名", length = 12)private String username;@Testpublic void testMyField(){// 获取类模板Class c = MyFieldTest.class;// 获取所有字段for(Field f : c.getDeclaredFields()){// 判断这个字段是否有MyField注解if(f.isAnnotationPresent(MyField.class)){MyField annotation = f.getAnnotation(MyField.class);System.out.println("字段:[" + f.getName() + "], 描述:[" + annotation.description() + "], 长度:[" + annotation.length() +"]");}}}}
5.2.1 应用场景一:自定义注解+拦截器 实现登录校验
自定义注解@LoginRequired,提示用户该接口需要登录才能访问,否则不需要登录。 ```java @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface LoginRequired {
}
```java@RestControllerpublic class IndexController {@GetMapping("/sourceA")public String sourceA(){return "你正在访问sourceA资源";}@GetMapping("/sourceB")public String sourceB(){return "你正在访问sourceB资源";}}
public class SourceAccessInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("进入拦截器了");return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}}
@Configurationpublic class InterceptorTrainConfigurer implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new SourceAccessInterceptor()).addPathPatterns("/**");}}
@RestControllerpublic class IndexController {@GetMapping("/sourceA")public String sourceA(){return "你正在访问sourceA资源";}@LoginRequired@GetMapping("/sourceB")public String sourceB(){return "你正在访问sourceB资源";}}
@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("进入拦截器了");// 反射获取方法上的LoginRequred注解HandlerMethod handlerMethod = (HandlerMethod)handler;LoginRequired loginRequired = handlerMethod.getMethod().getAnnotation(LoginRequired.class);if(loginRequired == null){return true;}// 有LoginRequired注解说明需要登录,提示用户登录response.setContentType("application/json; charset=utf-8");response.getWriter().print("你访问的资源需要登录");return false;}
5.2.2 应用场景二:自定义注解+AOP 实现日志打印
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>
@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface MyLog {}
@Aspect // 1.表明这是一个切面类@Componentpublic class MyLogAspect {// 2. PointCut表示这是一个切点,@annotation表示这个切点切到一个注解上,后面带该注解的全类名// 切面最主要的就是切点,所有的故事都围绕切点发生// logPointCut()代表切点名称@Pointcut("@annotation(me.zebin.demo.annotationdemo.aoplog.MyLog)")public void logPointCut(){};// 3. 环绕通知@Around("logPointCut()")public void logAround(ProceedingJoinPoint joinPoint){// 获取方法名称String methodName = joinPoint.getSignature().getName();// 获取入参Object[] param = joinPoint.getArgs();StringBuilder sb = new StringBuilder();for(Object o : param){sb.append(o + "; ");}System.out.println("进入[" + methodName + "]方法,参数为:" + sb.toString());// 继续执行方法try {joinPoint.proceed();} catch (Throwable throwable) {throwable.printStackTrace();}System.out.println(methodName + "方法执行结束");}}
@MyLog@GetMapping("/sourceC/{source_name}")public String sourceC(@PathVariable("source_name") String sourceName){return "你正在访问sourceC资源";}


