自定义注解其实非常简单,共3步,重点是2和3步
1、定义注解类,用于标识目标位置
2、拦截目标,为拿到目标字节码对象,这里重点是怎么拦截,根据场景不同使用不同拦截技术
参考:Java三大器:过滤器、监听器、拦截器_墨殇离陌的博客-优快云博客
- 使用AOP(只能拦截方法)
- 使用Filter(只能在有Servlet 中使用,只能是web应用使用)
- 使用拦截器
- 使用动态代理
3、拿到字节码对象,利用反射技术对对象内部结构进行改造。
举个栗子,这个例子功能没有啥实际作用,用来参考:
注解在方法形参上,可将String时间戳转换成-->指定String日期格式,如格式转换失败则不做操作
定义注解类
@Target({ElementType.PARAMETER}) //作用在方法参数上
@Retention(RetentionPolicy.RUNTIME)
public @interface TransitionDate {
String value() default "yyyy-MM-dd HH:mm:ss";
}
使用aop拦截和反射处理
@Component
@Aspect
public class TransitionDateAspect {
/**
* 注解在方法形参上,可将String时间戳转换成-->指定String日期格式,如格式转换失败则不做操作
*/
@Before("execution(public * icu.weizhan.service.*.*(..)))")
public void transitionDateOfParam(JoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
if (args.length == 0){
return; //没有参数不用解析
}
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod(); //这里获得方法对象才能使用getParameterAnnotations获取参数注解
//一个方法中有多个参数,一个参数中有多个注解,所以要用二维数组
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
//遍历多个参数
for (int i = 0; i < parameterAnnotations.length; i++) {
Object arg = args[i]; //形参
//遍历多个注解
for (Annotation annotation : parameterAnnotations[i]) {
if (annotation.annotationType().equals(TransitionDate.class)){
TransitionDate transitionDate = (TransitionDate) annotation;
String value = transitionDate.value(); //获取注解的value值
if (arg.getClass().equals(String.class)){
//转换
try {
Long aLong = Long.valueOf((String) arg);
Date date = new Date(aLong);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(value);
String format = simpleDateFormat.format(date);
//重新给形参赋值
Field field = arg.getClass().getDeclaredField("value");
field.setAccessible(true);
field.set(arg,format.toCharArray());
}catch (Exception e){
}
}
}
}
}
}
}
测试
public String test(@TransitionDate String date){
System.out.println(date);
return date;
}
@Test
public void transitionDateTest(){
transitionDateTest.test("1687452113476");
}