自定义注解
1. @Documented
用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员
2. @Inherited
元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
3. @Retention
定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对 Annotation的“生命周期”限制。
RetentionPolicy.RUNTIME 注解会在class字节码文件中存在,在运行时可以通过反射获取到
RetentionPolicy.CLASS 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得
RetentionPolicy.SOURCE 注解仅存在于源码中,在class字节码文件中不包含 如@OVerride 注解在源码(.java)文件中可以看到
4. @Target
说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。
ElementType.CONSTRUCTOR 作用于构造器
ElementType.FIELD 作用于域/属性
ElementType.LOCAL_VARIABLE 用于描述局部变量
ElementType.METHOD 作用于方法
ElementType.PACKAGE 用于描述包
ElementType.PARAMETER 用于描述参数
ElementType.TYPE 用于描述类、接口(包括注解类型) 或enum声明,最常用
示例代码
1通过继承ConstraintValidator
//注解声明
@Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Constraint(validatedBy = ValidPhoneNo.class) public @interface ValidatedPhoneNo { String message() default "手机号不匹配"; Class<?>[] groups() default {}; //入参 Class<? extends Payload>[] payload() default{}; } //注解实现 public class ValidPhoneNo implements ConstraintValidator<ValidatedPhoneNo, String> { private String needsValid; @Override public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) { System.out.println("comes to valid mobile number"); String regExp = "^((13[0-9])|(15[^4])|(18[0,2,3,5-9])|(17[0-8])|(147))\\d{8}$"; Pattern p = Pattern.compile(regExp); Matcher m = p.matcher(s); return m.matches(); } @Override public void initialize(ValidatedPhoneNo constraintAnnotation) { this.needsValid = constraintAnnotation.message(); } }
2通过拦截器,拦截被标准了注解的方法
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Subject subject = SecurityUtils.getSubject(); SessionUser sessionUser = (SessionUser)subject.getPrincipal(); if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod)handler; Method method = handlerMethod.getMethod(); UserEvent userEvent = (UserEvent)method.getAnnotation(UserEvent.class); if (null != userEvent && null != sessionUser) { String desc = StringUtils.isBlank(userEvent.desc()) ? "访问了" + method.getName() : userEvent.desc(); this.addUserEvent(request, desc, method.toString(), sessionUser); } } return true; }
3通过AOP
@Aspect @Component public class AdminLogAspect {
//连接点(切入点) @Pointcut("@annotation(com.**.AdminLog)") public void logPointCut() { } //通知 @Around("logPointCut()") public Object around(ProceedingJoinPoint point) throws Throwable { //执行方法 Object result = point.proceed(); //保存日志 saveSysLog(point); return result; } }