lombok原理以及简单的实现

lombok是一个简化Java代码的库,通过annotation processor在编译时起作用。本文介绍了如何在项目中配置lombok,以及如何创建一个简单的注解处理器。在处理器中,我们利用JavacTrees和TreeMaker来操作AST(抽象语法树),并在编译时对带有自定义注解的类进行处理。最后,注意到使用lombok时避免出现实例化对象的错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、什么是lombok

lombok是一个帮助我们简化代码的jar包,在idea中设置annotation processor保证二次编译的开启,下载安装lombok的插件,不然系统会认为你的代码在无中生有报错的?

lombok常见指令,@Data @Slf4j 等,这里就不一一列举了,网上有很多,请自己查阅,我们这里主要记录lombok的一个简单实现和原理。

二、简单实现

1.创建一个maven项目,并导入需要的jar包

<dependencies>
        <dependency>
            <groupId>com.google.auto.service</groupId>
            <artifactId>auto-service</artifactId>
            <version>1.0-rc4</version>
        </dependency>
        <dependency>
            <groupId>com.sun</groupId>
            <artifactId>tools</artifactId>
            <version>1.8</version>
            <scope>system</scope>
            <systemPath>${java.home}/../lib/tools.jar</systemPath>
        </dependency>
    </dependencies>

auto-service可以帮助我们执行processor,com.sun.tools是jdk本地的一个jar包必须加入此依赖才可以访问,或者是使用openjdk。

2.创建一个TestAnnotation注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface TestAnnotation {
}

这里值得说一下的是RetentionPolicy类型SOURCE表示在编译期运行。

3.然后就是核心的Processor

import com.google.auto.service.AutoService;
import com.sun.source.tree.Tree;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.tree.TreeTranslator;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Names;
import org.eclipse.jdt.core.dom.*;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import java.util.Set;

/**
 * Created with IntelliJ IDEA
 * Description:
 *      JSR269
 *
 * @author:duanshuangquan
 * @date:2019/3/11 12:07
 */
@AutoService(Processor.class)
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes({"*"})
public class TestProcessor extends AbstractProcessor {

    private Messager messager;
    private JavacTrees trees;
    private TreeMaker treeMaker;
    private Names names;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        System.out.println("**************** init ************* " );
        super.init(processingEnv);
        this.messager = processingEnv.getMessager();
        this.trees = JavacTrees.instance(processingEnv);
        Context context = ((JavacProcessingEnvironment)processingEnv).getContext();
        this.treeMaker = TreeMaker.instance(context);
        this.names = Names.instance(context);
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotation, RoundEnvironment roundEnv) {
        System.out.println("************ process ************************");
        Set<? extends Element> set = roundEnv.getElementsAnnotatedWith(TestAnnotation.class);
        for (Element element : set) {
            // 根据element的到tree
            JCTree jcTree = trees.getTree(element);
            jcTree.accept(new TreeTranslator(){
                @Override
                public void visitClassDef(JCTree.JCClassDecl jcClassDecl) {
                    // 增加一个字段
                    JCTree.JCVariableDecl jcVariableDecl = treeMaker.VarDef(treeMaker.Modifiers(Flags.PUBLIC + Flags.STATIC),
                            getNameFromString("log"),memberAccess("java.lang.String"),null);
                    // 惊天大坑 才发现 。。。和string一样并不操作自身要进行赋值
                    jcClassDecl.defs = jcClassDecl.defs.prepend(jcVariableDecl);
                    super.visitClassDef(jcClassDecl);
                }
            });
        }

        return true;
    }


    private com.sun.tools.javac.util.Name getNameFromString(String s) {
        return names.fromString(s);
    }

    private JCTree.JCExpression memberAccess(String components) {
        String[] componentArray = components.split("\\.");
        JCTree.JCExpression expr = treeMaker.Ident(getNameFromString(componentArray[0]));
        for (int i = 1; i < componentArray.length; i++) {
            expr = treeMaker.Select(expr, getNameFromString(componentArray[i]));
        }
        return expr;
    }
}

在编译的时候会执行,通过println可以了解到会先执行init方法再执行processor方法,自上而下的看首先是@AutoServer注解,来自于google的auto-service包其作用是在编译的时候会生成下面的一个文件结构,根据jsr269可以了解会根据此配置来执行Processor

             

 

@SupportedSourceVersion 是声明java版本的注解

@SupportedAnnotationTypes 用来声明注解,可以是类全名的数组也可以是通配符 *

接下在是init中初始化的参数

Messager 是用来避免重复打印日志的,先不进行考虑

JavacTrees 是java的ast语法树,TreeMaker是语法树的操作符,在com.sun.tools包下,一定要使用上下文唯一的一个。
Names 这里只是为了使用他的一个方法将string转为Name。

4.在其他项目中引入此jar包。并在类上加入TestAnnotation注解,然后编译,观察class会有不一样。

5.注意代码中的惊天大坑 他竟然new。。。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值