在本文中,我向您展示了本周偶然发现的产品的强大功能: Project Lombok使您能够在编译代码中修改字节码。 首先,我将详细介绍Lombok开箱即用的功能。 在本文的第二部分,我将描述如何扩展它以生成您自己的代码。
介绍
自从JEE诞生以来,就已经有人抱怨编码组件的复杂性。 我认为EJB v2是这种复杂性的一个很好的例子:对于一个简单的EJB,您必须提供EJB类本身以及每种访问类型(本地和远程)的宿主和接口。 这使其变得复杂,容易出错,并且更重要的是,您可以花更少的时间专注于真正的价值所在的业务代码。 两项举措表明了减少编码时所需的样板代码数量的意愿:
- Spring框架的座右铭是降低JEE的复杂性。 样板代码在Spring框架中编写一次,并且仅由项目使用。
- EJB v3已经考虑了Spring的经验,并旨在减少样板代码,从而不需要本地和远程接口。 最终,该规范的下一个版本将使本地和远程家庭也成为可选对象。
Lombok计划的目标与先前的计划完全相同,但为此目的,它使用了另一种机制。
批注处理
Java语言的版本5引入了注释,可以在编译时和/或运行时进行处理的代码元数据的概念。 不幸的是,在JDK 5中,在编译时处理注释是一个两步过程。 首先,您必须运行apt可执行文件来处理注释,也许创建或修改源文件,然后使用javac编译源。 那不是最好的方法,因此Java 6删除了apt并使得javac能够管理注释,从而简化了流程以获得更简单的单步计算。 这是Lombok采取的道路。
Lombok计划
Lombok的驱动功能是从注释中创建您需要的代码,以减少您必须编写的样板代码。 它为您提供以下注释,这些注释将永久更改您的代码(如果不是您的一生):
-
@Getter
和@Setter
:为您的字段创建getter和setter -
@EqualsAndHashCode
:实现equals()
和hashCode()
-
@ToString
:实现toString()
-
@Data
:使用先前的四个功能 -
@Cleanup
:关闭流 -
@Synchronized
:在对象上同步 -
@SneakyThrows
:引发异常
例如,在学习编码OO方式时,您被钻研来将您的字段设为私有,并编写了公共访问器来访问这些字段:
publicclassPerson{
privateStringname;
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
this.name=name;
}
}
由于编写起来很麻烦,因此某些(如果不是全部)IDE具有生成访问器的功能。 它有一些缺点:
- 如果您删除字段,则必须手动删除访问器
- 它用样板代码使您的真实代码混乱
- 推论:检查长类中的字段是否已经存在访问器确实需要付出很大的努力
此外,手动创建访问器很容易出错:我曾经花了几个小时寻找由同一个开发人员开发的代码中的错误,最后发现安装程序是错误的。
由于getter / setter只是字段的元数据,因此Lombok的态度是这样的:在Java中,元数据通过注释进行管理。 看下面的代码:
importorg.lombok.Getter;
importorg.lombok.Setter;
publicclassPerson{
@Getter@Setter
privateStringname;
}
我反编译了生成的类(使用JAD ),它创建了完全相同的字节码,只有源代码更简洁,更不易出错。
思考时,我发现了3个反对使用Lombok的论点:
- 反对使用这种策略的第一个论点是,您不能创建这样的受保护的访问器。 您错了,Lombok是可配置的:
importlombok.AccessLevel; importorg.lombok.Getter; importorg.lombok.Setter; publicclassPerson{ @Getter@Setter(AccessLevel.PROTECTED) privateStringname; }
对于所有提供的注释都是如此! 看看他们 。
- 反对使用Lombok的第二个论点是,您不知道它在幕后做什么。 的确如此,但是对于AOP或CGLIB或您使用的任何框架也可以这样说。
- 最后一个参数和恕我直言,唯一有效的方法是它使调试更加复杂:但是Spring在整个代码中使用的Java动态代理也是如此,而且仍有许多项目使用它们。
使用与安装
使用Lombok(Lombok)是一个三步过程:
- 将JAR放在类路径上
- 添加您要使用的注释
- 用javac编译
不过有一个陷阱。 请注意最后一个语句以及对javac的强调。 由于您和我认识的大多数(如果不是全部)开发人员都只专注于生产力,因此您可能正在使用IDE。 我不了解NetBeans和其他伙伴,但是我最喜欢的IDE Eclipse不使用javac进行编译,而是使用其自己的内部编译器。
我们来自Lombok的朋友对此进行了思考,Lombok也能够加入Eclipse编译过程。 为此,只需启动lombok.jar并按照屏幕上的说明进行操作即可:它将仅向eclipse.ini添加2行。
忠告(因为我犯了错误):如果使用带有参数的命令(例如Windows快捷方式)启动Eclipse,则这些参数优先,并且eclipse.ini被静默忽略。 只是让你知道...
Lombok扩展
据我所知,目前只有Lombok的一个扩展名叫Morbok。 它使您可以仅使用注释来创建经典的private static final
记录器。
这样做的好处是Morbok自动使用完全限定的类名作为记录器的名称,因此不会再出现复制粘贴错误。 缺点是,如果在记录框架时不使用Commons Logging,则必须使用要使用的框架配置每个@Logger
批注,没有整体配置:恕我直言,下一个版本中可能会涉及到这一点(有一个)。
建筑
首先,Lombok需要JDK 6进行编译,因为注释处理是使用APT在Java 5中完成的。 现在,Lombok在环境为该类构建AST之后立即进入编译过程。
然后,它将这样形成的结构传递给每个引用的处理程序。 有每个注释的单个处理程序: HandleGetter
为@Getter
, HandlerSetter
为@Setter
等。 猜猜处理程序负责处理注释。
扩展Lombok
扩展Lombok是一个三步过程:
- 创建注释。 由于注释是在编译时使用的,因此以后可以安全地将其丢弃,因此可以将其保留策略保留为其默认值(即
RetentionPolicy.SOURCE
)。 - 创建处理程序。 处理程序是直接实现
lombok.javac.JavacAnnotationHandler<T extends Annotation>
。 为什么直接? 因为Lombok使用ServiceProvider服务,这是其局限性之一 - 在META-INF / services下的名为
lombok.javac.JavacAnnotationHandler
的文件中lombok.javac.JavacAnnotationHandler
处理程序的标准类名称。
真正的编码发生在步骤2中:接口具有单个方法handle(AnnotationValues<T> annotation, com.sun.tools.javac.tree.JCTree.JCAnnotation ast, JavacNode annotationNode)
。 注意第二个参数包? 它表示Sun私有实施。 它有一些很大的缺点:
- 如果不是完全不可用,该文档将很少。 你在这里进入未知领域
- 由于
com.sun.tools.javac
不是公共API的一部分,因此可以随时更改。 您可以在每次更新时破坏代码 - 还记得以前提到过,这仅对Java有好处吗? 还是这样 如果您希望这个新注释在Eclipse下工作,那是另一个要编写的处理程序
例
例如,我为@Delegate
注释编码了一个胚胎。 在字段上的此类注释指示声明类应具有与该字段的类相同的公共方法,并且每个方法的主体都应是对其委托方法的调用。
publicclassDelegator{
@Delegate
privateDelegateObjectobject;
...
}
publicclassDelegateObject{
publicvoiddoSomething(){
...
}
}
前面的代码应生成与以下代码相同的字节码:
publicclassDelegator{
privateDelegateObjectobject;
publicvoiddoSomething(){
object.doSomething();
}
...
}
到目前为止:
- 它不处理泛型
- 提供的唯一处理程序是针对javac的
- 它是不可配置的
最终的实现留给了勇敢的读者:原始资源在这里是Eclipse / Maven格式。
结论
Lombok可以很快做出一些改进。 首先,我不喜欢JAR具有的整体结构。 恕我直言,它可以很好地分解为3个独立的JAR:Lombok代理本身,提供的注释和关联的处理程序,最后是安装程序。
而且,为每个注释编码两个处理程序会浪费时间。 如果您也需要支持NetBeans怎么办? 也许使用服务提供商是错误的...
最后,依赖Sun内部编译器API的风险太大。 我认为,如果Lombok可以为该API提供外观,则企业走这条路的风险可能会较小,并且可以由了解API的人员(Lombok团队)而非基础开发人员(例如我自己)来进行桥接。
总而言之,尽管存在这些缺陷,Lombok看起来还是一个非常有前途的项目,可以很好地模仿Spring的成功。 无论如何,这是我希望的,因为它是真正的横向思考,可以带来更多的附加值:祝未来好运!
翻译自: https://blog.frankel.ch/lombok-reduces-your-boilerplate-code/