Java自定义注解 用处很多 很多地方都可以使用到
Java注解是什么?
Java注解又称Java标注,是JDK5.0版本开始支持加入源代码的特殊语法元数据。
Java语言中的类、方法、变量、参数和包等都可以被标注。和Javadoc不同,Java标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java虚拟机可以保留标注内容,在运行时可以获取到标注内容。 当然它也支持自定义Java标注。
元注解 通过元注解 进行自定义注解
注解处理类:既然上面定义了注解,那得有办法拿到我们定义的注解啊。
java.lang.reflect.AnnotationElement
接口则提供了该功能。注解的处理是通过java反射来处理的。如下,反射相关的类Class, Method, Field都实现了AnnotationElement接口。
常用元注解
Target:描述了注解修饰的对象范围,取值在
java.lang.annotation.ElementType
定义,常用的包括:
- METHOD:用于描述方法
- PACKAGE:用于描述包
- PARAMETER:用于描述方法变量
- TYPE:用于描述类、接口或enum类型
Retention: 表示注解保留时间长短。取值在
java.lang.annotation.RetentionPolicy
中,取值为:
- SOURCE:在源文件中有效,编译过程中会被忽略
- CLASS:随源文件一起编译在class文件中,运行时忽略
- RUNTIME:在运行时有效
只有定义为
RetentionPolicy.RUNTIME
时,我们才能通过注解反射获取到注解。
案例一:自定义注解+拦截器 实现登录校验
1.注解
/**
* Created with ShawnWang.
*
* @Author: ShawnWang
* @Date: 2021-12-08 17:22
* @Description: 登录拦截校验注解
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginRequest {
}
2.拦截器
/**
* Created with ShawnWang.
*
* @Author: ShawnWang
* @Date: 2021-12-08 17:26
* @Description:
*/
public class SourceAccessInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.err.println("已经进入拦截器了");
// 反射获取方法上的LoginRequest注解
HandlerMethod handlerMethod = (HandlerMethod)handler;
LoginRequest loginRequired = handlerMethod.getMethod().getAnnotation(LoginRequest.class);
if(loginRequired == null){
return true;
}
// 有LoginRequest注解说明需要登录,提示用户登录
response.setContentType("application/json; charset=utf-8");
response.getWriter().print("你访问的资源需要登录");
return false;
}
@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 {
}
}
3.Controller 中请求方法
/**
* Created with ShawnWang.
*
* @Author: ShawnWang
* @Date: 2021-12-08 17:24
* @Description:
*/
@RestController
public class IndexController {
@GetMapping("/sourceOne")
public String sourceOne() {
return "A计划资源访问ing....";
}
@LoginRequest
@GetMapping("/sourceTwo")
public String sourceTwo() {
return "B计划资源访问ing....";
}
}
4.效果
sourceOne请求时
sourceTwo请求时 (因为在sourceTwo请求 加了自定义注解)
案例二:自定义注解+AOP 实现日志打印
1.定义注解 MyLog
/**
* Created with ShawnWang.
*
* @Author: ShawnWang
* @Date: 2021-12-08 17:43
* @Description:
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLog {
}
2.定义一个切面
/**
* Created with ShawnWang.
*
* @Author: ShawnWang
* @Date: 2021-12-08 17:44
* @Description:
*/
@Aspect
@Component
public class MyLogAspect {
/**
* 声明切点
*/
@Pointcut("@annotation(com.qust.base64andimgage.logannon.MyLog)")
public void logPointCut(){};
/**
* 环绕通知
* @param point
*/
@Around("logPointCut()")
public void logAround(ProceedingJoinPoint point){
//获取方法名称
String methodName = point.getSignature().getName();
//获取入参
Object[] args = point.getArgs();
StringBuilder sb = new StringBuilder();
for (Object arg : args) {
sb.append(arg + "; ");
}
System.out.println("进入[" + methodName + "]方法,参数为:" + sb.toString());
try {
point.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
}
}
3.Controller请求方法
@MyLog
@GetMapping("/sourceThree")
public String sourceC(String name){
return "C计划资源访问ing....";
}
4.效果