应用场景
在开发过程中我们会遇到需要使用自定义注解的需求,比如记录后台操作日志、接口权限检查等。
元注解
用来修饰注解的注解叫做元注解。
常用的元注解有@Target、@Retention、@Documented、@Inherited
@Target 定义注解的使用目标,也就是能被哪些Java元素所使用。它需要 ElementType 枚举来定义。
/**
* @Target
**/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
/**
* ElementType
**/
public enum ElementType {
/** 类、接口(包括注解类型),或者枚举 */
TYPE,
/** 属性 */
FIELD,
/** 方法 */
METHOD,
/** 方法形参 */
PARAMETER,
/** 构造参数 */
CONSTRUCTOR,
/** 局部变量 */
LOCAL_VARIABLE,
/** 注解 */
ANNOTATION_TYPE,
/** 包 */
PACKAGE,
/** 类型变量 */
TYPE_PARAMETER,
/** 任何使用类型(例如声明语句、泛型和强制转换语句中的类型) */
TYPE_USE
}
@Retention定义注解的生命周期。它需要 RetentionPolicy 枚举来定义。
/**
* @Retention
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}
/**
* RetentionPolicy
*/
public enum RetentionPolicy {
/**
* 注解将被编译器忽略,只在源文件中能看到
*/
SOURCE,
/**
* 注解会被编译到Class文件中,但JVM会忽略它
*/
CLASS,
/**
* 由JVM加载,包含在类文件中,在运行时可以被获取到,实际开发中用到的基本上都是这个
*/
RUNTIME
}
@Documented定义自定义注解是否生成到JavaDoc文档中。
@Inherited使用此注解后,子类也会拥有这个注解。只有当@Target被定义为ElementType.TYPE时起作用
自定义注解
/**
* 后台操作日志注解
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {
/**
* 描述
*/
String value();
//设置默认值方式
//String test() default "aaaa";
}
通过AOP方式保存操作日志
@Slf4j
@Aspect
@AllArgsConstructor
public class SysLogAspect {
@SneakyThrows
@Around("@annotation(sysLog)")
public Object around(ProceedingJoinPoint point, SysLog sysLog) {
String strClassName = point.getTarget().getClass().getName();
String strMethodName = point.getSignature().getName();
log.warn("[类名]:{},[方法]:{}", strClassName, strMethodName);
//从request中获取请求参数,保存操作日志
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
.....
return point.proceed();
}
}
//注入SysLogAspect
@Bean
public SysLogAspect sysLogAspect() {
return new SysLogAspect();
}
通过拦截器方式保存操作日志
/**
* 操作日志拦截器
*/
public class SysLogInterceptor extends HandlerInterceptorAdapter {
@Inject
private SysLogService sysLogService;
/**
* 请求前处理
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
SysLog sysLog = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), SysLog.class);
if (sysLog != null) {
//封装操作日志记录,保存到request中
SysLogEntity sysLogEntity = new SysLogEntity();
...
request.setAttribute("SYS_LOG", sysLogEntity);
}
}
return super.preHandle(request, response, handler);
}
/**
* 请求后处理
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
SysLog sysLog = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), SysLog.class);
if (sysLog != null) {
SysLogEntity sysLogEntity = (SysLogEntity) request.getAttribute("SYS_LOG");
if (sysLogEntity != null && sysLogEntity.getId() == null) {
sysLogService.create(sysLogEntity);
}
}
}
}
}