1. 上一篇 [使用aop和反射对controller方法入参进行格式化(简化版)]中,功能已经实现了,但是存在扩展性的问题:
自定义注解和processor的绑定工作在Enum中完成,它的扩展性是非常差的。后面我们将该功能封装为jar包之后,该如何暴露接口来扩展呢(Enum是存在jar包中的,无法动态添加)
2. 摒弃Enum做绑定
- 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());
} else {
annotations.addAll(i.getHandleAnnotations());
}
});
return annotations;
}
上述代码遍历processors获取存放的annotations
- 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中,下面贴一下修改的代码
- 顶级接口FormatterProcessor
public interface FormatterProcessor {
void format(Object obj, Field field, Annotation annotation) throws Exception;
}
- 抽象实现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;
}
}
- 自定义注解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);
}
}
- 自定义注解包装类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);
}
}
- 切面VoAspect
@Slf4j
@Aspect
@Component
public class VoAspect {
@Autowired
Set<? extends AbstractFormatterProcessor> processors;
@Around("execution(public * *..controller.*.*(..))")
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];
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. 遗留
暂不支持集合属性的格式化
|