编译期间生成代码(Lombok原理)

发布于:2024-06-17 ⋅ 阅读:(108) ⋅ 点赞:(0)

通过在编译期间,修改Java的AST(Abstract Syntax Tree)树,可以往类中,添加/修改(覆盖)方法、属性等。

现在比较常见的三方依赖例子有:Lobbok的@Data可以生成get、set方法,@Sl4j2可以生成静态常量log。

这篇文章,主要通过代码展示如何生成get、set方法。

编写一个只在编译期存在的注解:

import java.lang.*;

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

注解增强器

Java 编译器对注解的操作,是通过继承AbstractProcessor来实现的。如下是一个添加setter方法:

流程:

  1. 初始化参数操作,见init方法
  2. 在process方法中。生成方法。
  3. 先获取注解元素集合:
  4. 将注解元素转成class定义元素集合:
  5. 最后遍历class元素集合,获取其属性,并生成方法,修改dsfs树。

过程代码涉及信息泄密,忽略。

配置注解增强器

遵循SPI(Service Provider interface),在resources/META-INF/services中配置注解增强器,项目结构结构如下:
先忽略

文件的内容如下,如果有多个增强器,按行配置即可:

incremental.annotation.processors:

com.huawei.fbb.cool.aspect.cool.data.DataProcessor,isolating1

javax.annotation.processing.Processor:

com.huawei.fbb.cool.aspect.cool.data.DataProcessor

效果

参考@Data编译后的class文件

补充说明

由于是编译时注解,注解增强器,一定要单独一个项目(项目A),然后打包给其它服务引用(项目B)。

项目A的pom:

    <dependencies>
        <dependency>
            <groupId>com.sun</groupId>
            <artifactId>tools</artifactId>
            <version>1.8</version>
            <scope>system</scope>
            <systemPath>${java.home}/../lib/tools.jar</systemPath>
        </dependency>
    </dependencies>
    
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                    </configuration>
                    <executions>
                        <execution>
                            <id>default-compile</id>
                            <configuration>
                                <compilerArgument>-proc:none</compilerArgument>
                            </configuration>
                        </execution>
                        <execution>
                            <id>compile-project</id>
                            <phase>compile</phase>
                            <goals>
                                <goal>compile</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>

            </plugins>

        </pluginManagement>

    </build>

其中关于配置,可以用谷歌的 AutoService

当前缺陷

由于往AST插入方法元素,没有判断是否依据存在此类方法,所以很可能覆盖掉之前类中已经存在的方法

解决

增加方法之前,最好先判断一下是否已经含有这个的方法,如果有,就不插入。