> 文章列表 > 手把手实现一个lombok

手把手实现一个lombok

手把手实现一个lombok

手把手实现一个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.concurrentjava.util.concurrent.atomicjava.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,其原理如下:

手把手实现一个lombok

二、实现步骤

1.工程与环境依赖

  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>

注意细节

  1. Lombok项目本身要加 编译 参数 ,防止编译处理器无法实例化:-proc:none
  2. 要添加编译 类路径 bootclasspath: 指定tool.jar
  3. 在测试的时候 要构建一个新的工程,用一个新的IDEA窗口打开

2.注解处理器

  • 打印编译信息
  1. 编写注解处理器,实现AbstractProcessor
  2. 基于SPI指定处理器的路径 :工程/resources/META-INF/services/javax.annotation.processing.Processor
  3. 打印消息的时候,maven 用System.out, idea用Messager
  4. 我当时用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 {@Overridepublic synchronized void init(ProcessingEnvironment processingEnv) {System.out.println("这是我的第一人编译注释处理器");processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,"这是我的处理器");}@Overridepublic 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; // 获取 JcTreeprivate TreeMaker treeMaker; // 构建生成 jcTreeprivate Names names;@Overridepublic 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);}@Overridepublic 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(){@Overridepublic 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 {
}

编译后到效果
手把手实现一个lombok

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>