手把手实现一个lombok
- 一、lombok原理 JSR269
- 二、实现步骤
- 1.工程与环境依赖
- 注意细节
- 2.注解处理器
- 3.注解
- 4.jcTree 修改语法
- 4.新建模块依赖我们这个jar包进行编译
- 5.源码调试
一、lombok原理 JSR269
什么是JSR ?
JSR是Java Specification Requests的缩写,意思是Java 规范提案。是指向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求。任何人都可以提交JSR,以向Java平台增添新的API和服务。
有超过300的JSR。一些更为明显的JSRs包括:
| 的JSR# | 规格或技术 |
|---|---|
| 1 | 实时规范为Java(RTSJ规范)1.0 |
| 3 | Java管理扩展(JMX)的1.0,1.1和1.2 [ 2 ] |
| 5 | Java API的XML处理(JAXP)1.0 |
| 8 | OSGI的开放服务网关规范 |
| 9 | 次郎(联邦管理体系规范)1.0 |
| 12 | Java数据对象(JDO的)1.0 |
| 13 | 改进的BigDecimal(Java平台,标准版#java.math) |
| 14 | 加入到Java编程语言(如J2SE 5.0的泛型类型) |
| 16 | Java EE连接器架构(JCA)的1.0 |
| 19 | 企业JavaBeans(EJB)2.0 |
| 22 | JAIN SLEE API规范(JSLEE)的1.0 |
| 30 | 连接有限设备配置(CLDC)1.0 的Java ME |
| 31 | 用于XML绑定的Java体系结构(JAXB)的1.0 |
| 32 | JAIN SIP API规范(JSIP)的1.0,1.1和1.2的Java ME |
| 36 | 连接设备配置(CDC)的1.0为Java ME |
| 37 | 移动信息设备描述(MIDP)1.0为Java ME |
| 40 | Java元数据接口(JMI)1.0 |
| 41 | 一个简单的断言基金(J2SE 1.4中) |
| 47 | 日志 API规范(J2SE 1.4中) |
| 48 | WBEM服务规范(J2SE 1.4中) |
| 51 | 新的I / O API的Java平台(J2SE 1.4的)(妞妞) |
| 52 | JavaServer Pages标准标记库(JSTL)的1.0和1.1 [ 3 ] |
| 53 | 的Java Servlet 2.3和JavaServer页面(JSP)的1.2规格 |
| 54 | Java数据库连接(JDBC)3.0 |
| 56 | Java网络启动协议和API(JNLP的),1.0,1.5和6.0 [ 4 ](Java Web Start的) |
| 58 | Java 2平台企业版(J2EE)的1.3 |
| 59 | Java 2平台标准版(J2SE)的1.4(梅林) |
| 63 | 用于XML处理的Java API(JAXP)1.1和1.2 [ 5 ] |
| 68 | Java平台Micro版(Java ME)的1.0 |
| 73 | Java数据挖掘 API(JDM)1.0 |
| 75 | J2ME平台的PDA可选包 |
| 80 | 的Java 的USB API |
| 82 | 蓝牙的Java API |
| 88 | Java EE的应用程序部署 |
| 93 | 用于XML注册的Java API(JAXR)1.0 |
| 94 | Java规则引擎API |
| 102 | Java的文档对象模型(JDOM的)1.0 |
| 110 | Java API的WSDL(WSDL4J)1.0 |
| 112 | Java EE连接器架构(JCA)的1.5 |
| 113 | 的Java Speech API的2(JSAPI2) |
| 114 | Java数据库连接(JDBC)的RowSet实现 |
| 116 | 的SIP Servlet API 1.0 |
| 118 | 移动信息设备描述(MIDP)2.0为Java ME |
| 120 | 无线消息API(WMA)的 |
| 121 | 应用程序隔离API |
| 127 | 的JavaServer Faces(JSF)的1.0和1.1 [ 6 ] |
| 133 | Java内存模型和主题规范修订 |
| 135 | Java ME的Java移动媒体API(MMAPI)的 |
| 139 | 有限连接设备配置(CLDC)1.1为Java ME |
| 140 | 服务定位协议 “(SLP)的Java API |
| 141 | 会话描述协议(SDP)的API为Java |
| 151 | Java 2平台企业版(J2EE)的1.4 |
| 152 | JavaServer页面(JSP)的2.0 |
| 153 | 企业JavaBeans(EJB)2.1 |
| 154 | 的Java Servlet 2.4和2.5规格[ 7 ] |
| 160 | Java管理扩展(JMX)的远程API 1.0 |
| 166 | 并发实用程序(J2SE 5.0中的java.util.concurrent,java.util.concurrent.atomic和java.util.concurrent.locks) |
| 168 | Portlet规范 1.0 |
| 170 | 内容库的Java API(JCR)的1.0 |
| 172 | Java ME的Web服务规范 |
| 173 | 使用StAX(XML的流式API) |
| 175 | 一个Java编程语言的元数据工具 |
| 176 | Java 2平台标准版(J2SE)的5.0(虎) |
| 177 | J2ME(SATSA的安全和信任服务API) |
| 179 | 位置API为Java ME 1.0 |
| 180 | 会话发起协议(SIP)API为Java ME |
| 181 | 用于Java平台的Web服务元数据 |
| 184 | 移动3D图形API为Java ME 1.0和1.1 |
| 185 | 无线行业Java技术(JTWI的) |
| 187 | 即时消息(的Java ME和Java SE中) |
| 198 | 一个标准扩展API 的集成开发环境 |
| 199 | Java编译器 API |
| 201 | 扩展Java编程语言的枚举,自动装箱,静态导入循环和增强(J2SE 5.0的) |
| 202 | Java类文件规范更新 |
| 203 | 更多新的I / O API的Java平台(NIO2) |
| 204 | Unicode增补字符支持(增加了J2SE 5.0的支持Unicode的 3.1) |
| 205 | 无线消息API 2.0 “(WMA)2.0 |
| 206 | 用于XML处理的Java API(JAXP)1.3 |
| 208 | Java业务集成(JBI)的1.0 |
| 215 | Java社区进程(JCP)2.6 |
| 218 | 连接设备配置(CDC)的1.1为Java ME |
| 220 | 企业JavaBeans(EJB)3.0 |
| 221 | Java数据库连接(JDBC)4.0 |
| 222 | 用于XML绑定(JAXB)的2.0 Java体系结构 |
| 223 | Java SE 6中Java平台的脚本 |
| 224 | XML Web服务的Java API(JAX-WS的),继承的JAX-RPC |
| 225 | 的XQuery API为Java(XQJ的) |
| 226 | 可调节2D矢量图形 API 的Java ME |
| 229 | 支付API(PAPI的) |
| 231 | 针对OpenGL的Java绑定 |
| 234 | 高级多媒体补充 API为Java ME |
| 235 | 服务数据对象(SDO), |
| 239 | OpenGL ES的Java绑定 |
| 240 | JAIN SLEE API规范(JSLEE)的1.1 |
| 241 | Groovy编程语言 |
| 243 | Java数据对象(JDO的)2.0 |
| 244 | 的Java平台企业版(Java EE)的5 |
| 880 | JavaServer页面(JSP)的2.1 |
| 247 | Java数据挖掘 API(JDM)2.0 |
| 248 | 移动服务架构 |
| 249 | 移动服务架构2 |
| 250 | 常见的注解的Java平台(Java元数据设施) |
| 252 | 的JavaServer Faces(JSF)的1.2 |
| 253 | 移动电话服务API(MTA), |
| 255 | Java管理扩展(JMX)2.0 |
| 256 | 移动传感器API |
| 257 | 非接触式通信API(NFC技术) |
| 260 | Javadoc的标签技术更新 |
| 269 | 可插拔注解处理API(Java元数据设施) |
| 270 | Java平台标准版(Java SE)的6(野马) |
| 271 | 移动信息设备描述(MIDP)3.0为Java ME |
| 274 | BeanShell的脚本语言 |
| 275 | 单位规范(见计量单位) |
| 276 | 设计时元数据的的JavaServer面临的组件 |
| 277 | Java模块系统 |
| 280 | 对于Java ME的XML API |
| 281 | IMS的服务API(见的IMS) |
| 282 | 为Java实时规范(RTSJ规范)1.1 |
| 283 | 内容库的Java API(JCR)的2.0 |
| 286 | Portlet规范 2.0 |
| 289 | 的SIP Servlet API 1.1 |
| 290 | Java语言与XML用户界面标记集成(XML用户界面) |
| 291 | 针对Java SE动态组件的支持(见的OSGi) |
| 292 | JavaTM平台上支持动态类型语言 |
| 293 | 位置API为Java ME 2.0 |
| 294 | 在Java编程语言的改进模块化支持 |
| 296 | Swing应用程序框架(Java SE 7中) |
| 299 | Java的上下文和依赖注入(焊接) |
| 301 | JSF Portlet的桥梁 |
| 303 | Bean验证 |
| 307 | 移动网络和移动数据API(截至7月正式计划,20日,2007年,但官方发布2。问:2008 |
| 308 | 注解的Java类型(Java SE的8) |
| 311 | RESTful Web服务的Java API(JAX-RS的)1.0和1.1 |
| 314 | 的JavaServer Faces(JSF)的2.0 |
| 316 | 的Java平台企业版(Java EE)的6 |
| 317 | Java持久性API(JPA)的2.0 |
| 322 | Java EE连接器架构(JCA)的1.6 |
| 325 | IMS通信促成(ICE)的(见的IMS) |
| 330 | 对Java的依赖注入 |
| 343 | Java消息服务 2.0(JMS) |
| 354 | Java的货币及货币的API |
| 901 | Java语言规范,第三版(JLS的)(J2SE 5.0的集成的JSR 14,41,133,175,201和204) |
| 907 | Java事务API(JTA),1.0和1.1 |
| 912 | Java 3D的 API 1.3 |
| 913 | Java社区进程(JCP)的2.0,2.1和2.5。[ 8 ] |
| 914 | Java消息服务(JMS)API的1.0和1.1 |
| 924 | 第二版(JVM)Java虚拟机规范(J2SE 5.0的)。[ 9 ] |
| 926 | 的Java 3D API 1.5 |
JSR269 可插拔的注解处理API,其原理如下:

二、实现步骤
1.工程与环境依赖
- 配置maven 插件,pom.xml 编译参数
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>8</source>
<target>8</target>
<encoding>UTF-8</encoding>
<compilerArgs>
<arg>-parameters</arg>
<arg>-proc:none</arg>
<arg>-XDignore.symbol.file</arg>
</compilerArgs>
<compilerArguments>
<bootclasspath>
${java.home}/lib/rt.jar${path.separator}${java.home}/lib/jce.jar${path.separator}${java.home}/../lib/tools.jar
</bootclasspath>
</compilerArguments>
<fork>true</fork>
</configuration>
</plugin>
</plugins>
</build>
注意细节
- Lombok项目本身要加 编译 参数 ,防止编译处理器无法实例化:-proc:none
- 要添加编译 类路径 bootclasspath: 指定tool.jar
- 在测试的时候 要构建一个新的工程,用一个新的IDEA窗口打开
2.注解处理器
- 打印编译信息
- 编写注解处理器,实现
AbstractProcessor - 基于SPI指定处理器的路径 :工程/resources/META-INF/services/javax.annotation.processing.Processor
- 打印消息的时候,maven 用System.out, idea用
Messager类 - 我当时用ide 编译时一直报错 ,我没太在意使用mvn 命令处理的, mvn命令没错误
Error:java: 服务配置文件不正确, 或构造处理程序对象javax.annotation.processing.Processor: Provider com.wfg.HelloProcessor not found时抛出异常错误
在项目编写的目录下操作下面的命令
mvn compile 编译
mvn package 打包
mvn install 安装到本地仓库
mvn exec:java -Dexec.mainClass="hello.HelloWorld" 运行main类,此处用不到这个命令
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes("com.wfg.MyHello")
public class HelloProcessor extends AbstractProcessor {
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
System.out.println("这是我的第一人编译注释处理器");
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,"这是我的处理器");
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
return false;
}
}
3.注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface MyHello {
}
4.jcTree 修改语法
- 构建一个hello world 语句
import com.sun.tools.javac.api.JavacTrees;
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.Names;
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import java.util.Set;
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes("org.myLombok.Hello")
public class HelloProcessor extends AbstractProcessor {
private JavacTrees javacTrees; // 获取 JcTree
private TreeMaker treeMaker; // 构建生成 jcTree
private Names names;
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
System.out.println("这是我的第一人编译注释处理器");
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,"这是我的处理器");
javacTrees = JavacTrees.instance(processingEnv);// 语法树
Context context = ((JavacProcessingEnvironment) processingEnv).getContext();
this.treeMaker = TreeMaker.instance(context);
super.init(processingEnv);
this.names = Names.instance(context);
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
annotations.stream()
.flatMap(t->roundEnv.getElementsAnnotatedWith(t).stream())
.forEach(t->{
JCTree tree = javacTrees.getTree(t);
// 基于访问者设计模式 去修改方法
tree.accept(new TreeTranslator(){
@Override
public void visitMethodDef(JCTree.JCMethodDecl tree) {
// System.out.println("hello world");
JCTree.JCStatement sysout = treeMaker.Exec(
treeMaker.Apply(
List.nil(),
select("System.out.println"),
List.of(treeMaker.Literal("hello world!")) // 方法中的内容
)
);
// 覆盖原有的语句块
tree.body.stats=tree.body.stats.append(sysout);
super.visitMethodDef(tree);
}
});
});
return true;
}
private JCTree.JCFieldAccess select(JCTree.JCExpression selected, String expressive) {
return treeMaker.Select(selected, names.fromString(expressive));
}
private JCTree.JCFieldAccess select(String expressive) {
String[] exps = expressive.split("\\.");
JCTree.JCFieldAccess access = treeMaker.Select(ident(exps[0]), names.fromString(exps[1]));
int index = 2;
while (index < exps.length) {
access = treeMaker.Select(access, names.fromString(exps[index++]));
}
return access;
}
private JCTree.JCIdent ident(String name) {
return treeMaker.Ident(names.fromString(name));
}
}
4.新建模块依赖我们这个jar包进行编译
/**
* @author wufagang
* @description
* @date 2023年04月18日 20:46
*/
@MyHello
public class HelloDemo {
}
编译后到效果

5.源码调试
测试模块引入下面的插件
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>



















