一、java生命周期
二、在编译期的时候检查代码中某些配置是否正常
2.1 引入maven依赖
<dependency>
<groupId>com.google.auto.service</groupId>
<artifactId>auto-service</artifactId>
</dependency>
AutoService是Google开发一个自动生成SPI文件的框架。
2.2 实现一个注解检查功能
我的代码里面有用到一个自己写的注解@Cache 里面有一个属性叫 allowOptionalEmptyValues,这个属性的作用是当被@Cache 修饰的方法返回类型如果是 Optional<T>的时候不要进行拆箱操作。但是方法的返回类型不是Optional<T>就没必要用这个属性,我想提醒用这个属性的人,就用java自带的编译期检查来实现这个提醒功能。
@SupportedAnnotationTypes("com.my.framework.cache.annotation.Cacheable") // 你的注解全路径
@SupportedSourceVersion(SourceVersion.RELEASE_8) // 你的Java版本,支持的最大java版本限制
@AutoService(Processor.class) // javax.annotation.processing.Processor 这个是Processor是Java内置的,Javac编译前默认的注解处理器接口
public class CacheableCompilerProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (TypeElement annotation : annotations) {
// processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "annotation: " + annotation.toString());
Set<? extends Element> annotatedElements = roundEnv.getElementsAnnotatedWith(annotation);
// 遍历被@Cacheable表示的属性或方法
for (Element annotatedMethodElement : annotatedElements) {
// processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "annotatedElements: " + annotatedMethodElement.toString());
if (annotatedMethodElement.getKind() != ElementKind.METHOD && annotatedMethodElement.getKind() != ElementKind.FIELD) {
continue;
}
// 获取方法上@Cacheable注解属性
Cacheable methodCacheable = annotatedMethodElement.getAnnotation(Cacheable.class);
if (Objects.isNull(methodCacheable)) {
continue;
}
// processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "methodCacheable: " + methodCacheable);
ExecutableElement roundMethodExecutableElement = ((ExecutableElement) annotatedMethodElement);
// 遍历出方法的修饰符如: public static void 等
String methodModifiersStr = roundMethodExecutableElement.getModifiers().stream().map(Modifier::toString).collect(Collectors.joining(" "));
TypeMirror returnType = roundMethodExecutableElement.getReturnType();
// 组装方法完整签名
String methodDescription = methodModifiersStr + " " + returnType + " " + annotatedMethodElement;
boolean hasOptionalReturnType = returnType.toString().startsWith("java.util.Optional");
if(methodCacheable.allowOptionalEmptyValues() && !hasOptionalReturnType) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,methodDescription +
" @Cacheable 注解的方法当属性 allowOptionalEmptyValues = true 时,返回类型必须为 java.util.Optional 类型! " +
"当前@cacheable allowOptionalEmptyValues = " + methodCacheable.allowOptionalEmptyValues(), annotatedMethodElement);
}
if (hasOptionalReturnType && methodCacheable.allowNullValues() && methodCacheable.allowOptionalEmptyValues()) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, methodDescription +
"注意:@Cacheable 注解的方法由于会拆包装包Optional返回值,当 allowNullValues=true 且 allowOptionalEmptyValues=true 时," +
"不论是null还是Optional包装的null对象都会被缓存!" +
" 当前@cacheable allowNullValues = " + methodCacheable.allowNullValues() +
", allowOptionalEmptyValues = " + methodCacheable.allowOptionalEmptyValues());
}
}
}
return true; // 表示注解已被处理,后续处理器不会再处理它们
}
}