使用aop和反射对controller方法入参进行格式化(通用版)

1. 上一篇 [使用aop和反射对controller方法入参进行格式化(简化版)]中,功能已经实现了,但是存在扩展性的问题:

自定义注解和processor的绑定工作在Enum中完成,它的扩展性是非常差的。后面我们将该功能封装为jar包之后,该如何暴露接口来扩展呢(Enum是存在jar包中的,无法动态添加)

2. 摒弃Enum做绑定

  1. FieldFormatterEnum.getFormatters(获取受支持的自定义注解集合)代替方案
@Autowired
Set<? extends AbstractFormatterProcessor> processors;
使用上述代码,在切面类中注入自定义注解的processors集合,将自定义注解和processor的绑定工作在processors中完成.
private Set<Class<? extends Annotation>> getSupportAnnotationTypes() {
        Set<Class<? extends Annotation>> annotations = new HashSet<>();
        this.processors.forEach((i) -> {
            Optional<Class<? extends Annotation>> any = i.getHandleAnnotations().stream().filter(annotations::contains).findAny();
            if (any.isPresent()) {
                log.error("muilti handle processor find for annotaion '{}'", any.get().getName());
//                throw new Exception(String.format("muilti handle processor find for annotaion '%s'", any.get().getName()));
            } else {
                annotations.addAll(i.getHandleAnnotations());
            }
        });
        return annotations;
    }
    上述代码遍历processors获取存放的annotations
  1. FieldFormatterEnum.getProcessorByAnnotation(根据自定义注解获取绑定的processor)代替方案
private Class<? extends AbstractFormatterProcessor> getProcessorByAnnotation(Class<? extends Annotation> annotationType) {
        Optional<? extends AbstractFormatterProcessor> first = processors.stream().filter((i) -> i.getHandleAnnotations().contains(annotationType)).findFirst();
        if (first.isPresent()) {
            return first.get().getClass();
        } else {
            return null;
        }
    }同样遍历processors获取到对应的processor

3. 由上引发的线程安全问题

AbstractFormatterProcessor子类修改为spring容器中bean,其中的属性就涉及线程安全问题
需要将属性转移到ArgElementMetadata中,下面贴一下修改的代码
  1. 顶级接口FormatterProcessor
public interface FormatterProcessor {

    void format(Object obj, Field field, Annotation annotation) throws Exception;
}
  1. 抽象实现AbstractFormatterProcessor
public abstract class AbstractFormatterProcessor implements FormatterProcessor {

    protected Set<Class<? extends Annotation>> handleAnnotations = new LinkedHashSet<>();

    @PostConstruct
    public void init() {
        this.setHandleAnnotations();
    }

    protected abstract void setHandleAnnotations();

    public Set<Class<? extends Annotation>> getHandleAnnotations() {
        return handleAnnotations;
    }
}
  1. 自定义注解processor
@Component
public class YMDtFormatterProcessor extends AbstractFormatterProcessor {

    @Override
    public void format(Object obj, Field field, Annotation annotation) throws Exception {
        ReflectionUtils.makeAccessible(field);
        Field[] declaredFields = obj.getClass().getDeclaredFields();
        String yoyDtName = "";
        String momDtName = "";
        String pattern = "";
        if (annotation.annotationType().isAssignableFrom(YMDtFormatter.class)) {
            momDtName = ((YMDtFormatter) annotation).momDtName();
            yoyDtName = ((YMDtFormatter) annotation).yoyDtName();
            pattern = ((YMDtFormatter) annotation).pattern();
        }
        Object curValue = field.get(obj);
        String finalYoyDtName = yoyDtName;
        String finalMomDtName = momDtName;
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);

        Arrays.stream(declaredFields).forEach(i->{
            if (StringUtils.isNotEmpty(finalYoyDtName) && finalYoyDtName.equals(i.getName())) {
                ReflectionUtils.makeAccessible(i);
                try {
                    Calendar now = Calendar.getInstance();
                    now.setTime(sdf.parse(String.valueOf(curValue)));
                    now.add(Calendar.MONTH, -1);
                    i.set(obj, sdf.format(now.getTime()));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (StringUtils.isNotEmpty(finalMomDtName) && finalMomDtName.equals(i.getName())) {
                ReflectionUtils.makeAccessible(i);
                try {
                    Calendar now = Calendar.getInstance();
                    now.setTime(sdf.parse(String.valueOf(curValue)));
                    now.add(Calendar.YEAR, -1);
                    i.set(obj, sdf.format(now.getTime()));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    @Override
    protected void setHandleAnnotations() {
        this.handleAnnotations.add(YMDtFormatter.class);
    }
}
  1. 自定义注解包装类ArgElementMetadata
@Data
@Accessors(chain = true)
public class ArgElementMetadata {
    /**
     * 集合处理优先级使用
     */
    private Integer order;

    /**
     * 属性字段
     */
    private Field arg;

    /**
     * 注入对象
     */
    private Object object;
    /**
     * 字段注解信息
     */
    private Annotation annotation;

    private AbstractFormatterProcessor processor;

    public void format() throws IllegalAccessException {
        this.processor.format(this.object,this.arg,this.annotation);
    }

}
  1. 切面VoAspect
@Slf4j
@Aspect
@Component
public class VoAspect {

    @Autowired
    Set<? extends AbstractFormatterProcessor> processors;

    @Around("execution(public * *..controller.*.*(..))")
//    TODO 切入具体参数注解
//            " && @args(cn.com.gome.bdc.data.platform.merchant.web.annotation.vo.EnableFormat)" +
    public Object VoFormat(ProceedingJoinPoint pjp) throws Throwable {
        Method method = ((MethodSignature) pjp.getSignature()).getMethod();
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        HashSet<Integer> positions = new HashSet<>();
        for (int i = 0; i < parameterAnnotations.length; i++) {
            Annotation[] annotations = parameterAnnotations[i];
            for (int j = 0; j < annotations.length; j++) {
                Annotation annotation = annotations[j];
                if (annotation.annotationType().isAssignableFrom(EnableFormat.class)) {
                    positions.add(i);
                    break;
                }
            }
        }
        Object vo;
        if (positions.size() > 0) {
            Object[] args = pjp.getArgs();
            for (Integer position : positions) {
                vo = args[position];
//            vo格式化
                Field[] fields = vo.getClass().getDeclaredFields();

                Set<Class<? extends Annotation>> supportAnnotations = getSupportAnnotationTypes();
                List<ArgElementMetadata> metadatas = new ArrayList<>();

                List<ArgElementMetadata> finalMetadatas = metadatas;
                Object finalVo = vo;
                Arrays.stream(fields).forEach(i -> {
                    Annotation[] filedAnnotations = i.getDeclaredAnnotations();
                    Arrays.stream(filedAnnotations).forEach(j -> {
                        if (supportAnnotations.contains(j.annotationType())) {
                            try {
                                buildArgMetadata(finalVo, i, j, finalMetadatas);
                            } catch (Exception e) {
                                log.error(e.getMessage());
                            }
                        }
                    });
                });

                metadatas = metadatas.stream().sorted(Comparator.comparingInt(ArgElementMetadata::getOrder)).collect(Collectors.toList());

                for (ArgElementMetadata metadata : metadatas) {
                    metadata.format();
                }
                args[position] = vo;
            }
            return pjp.proceed(args);
        } else {
            return pjp.proceed();
        }
    }

    private Set<Class<? extends Annotation>> getSupportAnnotationTypes() {
        Set<Class<? extends Annotation>> annotations = new HashSet<>();
        this.processors.forEach((i) -> {
            Optional<Class<? extends Annotation>> any = i.getHandleAnnotations().stream().filter(annotations::contains).findAny();
            if (any.isPresent()) {
                log.error("muilti handle processor find for annotaion '{}'", any.get().getName());
            } else {
                annotations.addAll(i.getHandleAnnotations());
            }
        });
        return annotations;
    }

    private void buildArgMetadata(Object vo, Field i, Annotation j, List<ArgElementMetadata> metadatas) throws Exception {
        final int[] order = new int[1];
        Arrays.stream(j.getClass().getDeclaredMethods()).filter(k -> "order".equals(k.getName())).findFirst()
                .ifPresent(g -> {
                    try {
                        order[0] = Integer.parseInt(String.valueOf(
                                g.invoke(j)
                        ));
                    } catch (IllegalAccessException | InvocationTargetException e) {
                        e.printStackTrace();
                    }
                });
        Class<? extends AbstractFormatterProcessor> processorClass = getProcessorByAnnotation(j.annotationType());
        if (Objects.isNull(processorClass)) {
            return;
        }
        metadatas.add(new ArgElementMetadata()
                .setOrder(order[0] > 0 ? order[0] : 5)
                .setArg(i).setProcessor(getProcessorBeanByAnnotation(j.annotationType())).setObject(vo).setAnnotation(j)
        );
    }

    private Class<? extends AbstractFormatterProcessor> getProcessorByAnnotation(Class<? extends Annotation> annotationType) {
        Optional<? extends AbstractFormatterProcessor> first = processors.stream().filter((i) -> i.getHandleAnnotations().contains(annotationType)).findFirst();
        if (first.isPresent()) {
            return first.get().getClass();
        } else {
            return null;
        }
    }

    private AbstractFormatterProcessor getProcessorBeanByAnnotation(Class<? extends Annotation> annotationType) {
        return processors.stream().filter((i) -> i.getHandleAnnotations().contains(annotationType)).findFirst().orElse(null);
    }
}

4. 遗留

暂不支持集合属性的格式化
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值