項(xiàng)目終于用上了插入式注解,真香!
共 9460字,需瀏覽 19分鐘
·
2024-06-26 09:19
往期熱門文章:
前言
需求
promethus來監(jiān)控現(xiàn)在公司內(nèi)使用各版本代碼庫的比例,希望達(dá)到的效果圖如下:
問題
@TrisceliVersion
public static final String version = "";
@TrisceliVersion
public static final String version = "1.0.31-SNAPSHOT";
解決
@Setter的實(shí)現(xiàn):
@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface Setter {
// 略...
}
@Setter的Retention是SOURCE類型的,也就是說這個(gè)注解只在編譯期有效,它甚至不會被編入class文件,所以lombok無疑是第一種解析方式,那用什么方式可以在編譯期就讓注解被解析到并執(zhí)行我們的解析代碼呢?答案就是定義插入式注解處理器(通過JSR-269提案定義的Pluggable Annotation Processing API實(shí)現(xiàn))
@Documented
@Retention(RetentionPolicy.SOURCE) //只在編譯期有效,最終不會打進(jìn)class文件中
@Target({ElementType.FIELD}) //僅允許作用于類屬性之上
public @interface TrisceliVersion {
}
AbstractProcessor的處理器:
/**
* {@link AbstractProcessor} 就屬于 Pluggable Annotation Processing API
*/
public class TrisceliVersionProcessor extends AbstractProcessor {
private JavacTrees javacTrees;
private TreeMaker treeMaker;
private ProcessingEnvironment processingEnv;
/**
* 初始化處理器
*
* @param processingEnv 提供了一系列的實(shí)用工具
*/
@SneakyThrows
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
this.processingEnv = processingEnv;
this.javacTrees = JavacTrees.instance(processingEnv);
Context context = ((JavacProcessingEnvironment) processingEnv).getContext();
this.treeMaker = TreeMaker.instance(context);
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
}
@Override
public Set<String> getSupportedAnnotationTypes() {
HashSet<String> set = new HashSet<>();
set.add(TrisceliVersion.class.getName()); // 支持解析的注解
return set;
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (TypeElement t : annotations) {
for (Element e : roundEnv.getElementsAnnotatedWith(t)) { // 獲取到給定注解的element(element可以是一個(gè)類、方法、包等)
// JCVariableDecl為字段/變量定義語法樹節(jié)點(diǎn)
JCTree.JCVariableDecl jcv = (JCTree.JCVariableDecl) javacTrees.getTree(e);
String varType = jcv.vartype.type.toString();
if (!"java.lang.String".equals(varType)) { // 限定變量類型必須是String類型,否則拋異常
printErrorMessage(e, "Type '" + varType + "'" + " is not support.");
}
jcv.init = treeMaker.Literal(getVersion()); // 給這個(gè)字段賦值,也就是getVersion的返回值
}
}
return true;
}
/**
* 利用processingEnv內(nèi)的Messager對象輸出一些日志
*
* @param e element
* @param m error message
*/
private void printErrorMessage(Element e, String m) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, m, e);
}
private String getVersion() {
/**
* 獲取version,這里省略掉復(fù)雜的代碼,直接返回固定值
*/
return "v1.0.1";
}
SPI機(jī)制被發(fā)現(xiàn),所以需要定義META.services:
測試
往期熱門文章:
1、只用Tomcat,不用Nginx行不行? 2、聽說你還在用Xshell? 3、驚艷到我的 10個(gè) MySQL高級查詢技巧! 4、我有點(diǎn)想用JDK17了 5、解放大腦:ChatGPT + PlantUML = 不用畫圖了 6、高逼格的SQL寫法:行行比較 7、限流算法哪家強(qiáng)?時(shí)間窗口,令牌桶與漏桶算法對比 8、每天都提交代碼,那你知道.git目錄內(nèi)部的秘密嗎? 9、我患上了空指針后遺癥 10、這10個(gè)小技巧讓你減少80%的Bug!
評論
圖片
表情
