1 注解是什么
注解本质是一个继承Annotation的特殊接口,只有被解析之后才会生效,常见的解析方法有两种:
- 编译期直接扫描:编译器在编译的时候扫描对应的注解并处理,比如某个方法使用@Override注解,在编译的时候就会检测当前的方法是否重写了父类对应的方法。
- 运行期通过反射处理:比如Spring框架的@Value、@Component都是通过反射来进行处理的。
2 自定义注解
只要理解和记住jdk内置的四个注解即可 (@Target,@Retention,@Documented,@Inherited)
- @Retention:保留的时间范围 (RetentionPolicy)
- SOURCE源文件保留(如@Override保留在源文件,编译后注解消失)
- CLASS编译时保留(如lombok生成get/set)
- RUNTIME运行时保留(如切面记录日志,或验证参数信息等)
- @Target:使用范围
- ElementType.FIELD
- ElementType.METHOD
- ElementType.PARAMETER
- ElementType.LOCAL_VARIABLE
- ElementType.TYPE_USE
- @Documented:保留注解信息
- @Inherited:子类注解自动继承该注解
3 注解实战
3.1 结合Spring拦截器实现用户权限校验
通过Spring拦截器拦截被自定义注解的方法,来实现功能:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginRequired {
// 不需要定义任何方法
}
定义了一个登陆注解。通过拦截器拦截请求时,判断是否添加了该注解,如果这个请求添加了该注解,那么就会去ThreadLocal中判断有没有保存当前用户的信息,没有的话就不放行请求,让用户去登陆先。
@Component
public class LoginRequiredInterceptor implements HandlerInterceptor {
@Autowired
private HostHolder hostHolder;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
LoginRequired loginRequired = method.getAnnotation(LoginRequired.class);
if (loginRequired != null && hostHolder.getUser() == null) {
response.sendRedirect(request.getContextPath() + "/login");
return false;
}
}
return true;
}
}
3.2 结合Spring AOP实现
定义一个注解
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Log {
}
定义切面:
@Component
@Aspect
@Slf4j
public class LogAspect {
@Pointcut(value = "@annotation(com.lrm.boot.hello.Log)")
public void log() {
}
@Around("log()")
public Object doAround(ProceedingJoinPoint joinPoint) {
Object obj = null;
try {
long beginTime = System.currentTimeMillis();
obj = joinPoint.proceed();
// 获取方法信息
String methodName = joinPoint.getSignature().getName();
String className = joinPoint.getSignature().getDeclaringTypeName();
log.info("类:[{}],方法:[{}]耗时时间为:[{}]", className, methodName, System.currentTimeMillis() - beginTime + "毫秒");
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return obj;
}
}