lombok的@Builder注解原理背后干了啥?

简介: lombok的@Builder注解原理背后干了啥?

在Lombok v0.12.0中作为实验功能引入

自v1.16.0起获得了 @Singular 支持并被升级到了主要lombok软件包

@Builder、@Singular自lombok v1.16.8起,使用可以添加明确的方法

@Builder.Default* v1.16.16中添加了功能

@Builder(builderMethodName = “”) 从=1.18.8开始是合法的(并且将抑制生成器方法的生成)

@Builder(access = AccessLevel.PACKAGE) 从lombok v1.18.8开始是合法的(并将生成具有指定访问级别的构建器类,构建器方法等)

功能

@Builder注解为你的类提供复杂的建造者模式 API。

@Builder 使你可以自动生成使您的类可实例化的代码,例如:

Person.builder()
  .name("AdamSavage")
  .city("SanFrancisco")
  .job("Mythbusters")
  .job("Unchained Reaction")
  .build();

使用位置

@Builder可以放在类,构造器或方法上。虽然“基于类”和“基于构造器”模式是最常见的用例,但使用“方法”用例最容易解释。

public class ResponseMessage extends Message<OperationResult> {
    private ResponseMessage(MessageHeader messageHeader, OperationResult messageBody) {
        super(messageHeader, messageBody);
    }
    public Class getMessageBodyDecodeClass(int opcode) {
        return OperationType.fromOpCode(opcode).getOperationResultClazz();
    }
    public static ResponseMessage.ResponseMessageBuilder builder() {
        return new ResponseMessage.ResponseMessageBuilder();
    }
    public ResponseMessage() {
    }
    public static class ResponseMessageBuilder {
        private MessageHeader messageHeader;
        private OperationResult messageBody;
        ResponseMessageBuilder() {
        }
        public ResponseMessage.ResponseMessageBuilder messageHeader(MessageHeader messageHeader) {
            this.messageHeader = messageHeader;
            return this;
        }
        public ResponseMessage.ResponseMessageBuilder messageBody(OperationResult messageBody) {
            this.messageBody = messageBody;
            return this;
        }
        public ResponseMessage build() {
            return new ResponseMessage(this.messageHeader, this.messageBody);
        }
        public String toString() {
            return "ResponseMessage.ResponseMessageBuilder(messageHeader=" + this.messageHeader + ", messageBody=" + this.messageBody + ")";
        }
    }
}

被**@Builder**注解的方法(从现在开始称为target)将生成以下7件事:

即构造内部类,在内部类赋值属性,build时调用含有所有属性的构造方法创建对象。


一个内部静态类,名为FooBuilder,其类型参数与静态方法相同(称为builder)

在构建器中:目标的每个参数有一个private非static 非 final 字段

在builder中:包私有的无参数空构造器

在builder中:对目标的每个参数使用类似 setter 的方法:与该参数具有相同的类型和相同的名称。它返回构建器本身,以便可以将setter调用链接起来

在builder中:build()调用该方法的方法,并在每个字段中传递。它返回与目标返回相同的类型

有意义的toString()实现

在包含target的类中:一个builder()方法,该方法创建builder的新实例

如果该元素已存在,则每个列出的生成元素都将被静默跳过(忽略参数计数并仅查看名称)。这包括构建器本身:如果该类已经存在,则lombok会简单地开始在此现有类中注入字段和方法,除非要注入的字段/方法当然已经存在。但是,您不能在生成器类上放置生成lombok批注的任何其他方法(或构造函数)。例如,您不能放入@EqualsAndHashCodebuilder类。

@Builder可以为收集参数/字段生成所谓的“奇异”方法。它们采用1个元素而不是整个列表,然后将该元素添加到列表中。例如:Person.builder().job(“Mythbusters”).job(“Unchained Reaction”).build();将导致该List jobs字段中包含2个字符串。要获得此行为,必须使用注释字段/参数@Singular。该功能具有其自己的文档。


现在,“方法”模式已经很清楚了,@Builder在构造函数上添加注释的功能类似。实际上,构造函数只是具有特殊语法以调用它们的静态方法:它们的“返回类型”是它们构造的类,并且它们的类型参数与类本身的类型参数相同。


应用于@Builder类就像是将其添加@AllArgsConstructor(access = AccessLevel.PACKAGE)到该类并将@Builder注释应用于此all-args-constructor一样。仅当您自己未编写任何显式构造函数时,此方法才有效。如果确实有显式构造函数,则将@Builder注释放在构造函数上而不是在类上。请注意,如果将@Value和@Builder都放在类上,则@Builder要生成“ wins”的程序包私有构造函数,而禁止@Value要生成的构造函数。


如果@Builder用于生成生成器来生成您自己的类的实例(除非添加@Builder到不返回您自己的类型的方法中,否则通常都是这种情况),您还可以@Builder(toBuilder = true)在类中使用生成实例方法toBuilder();它创建一个新的构建器,该构建器以该实例的所有值开始。您可以将@Builder.ObtainVia注释放在参数(对于构造函数或方法的情况)或字段(对于@Builder类型的情况)上,以指示从该实例获取该字段/参数的值的替代方法。例如,您可以指定要调用的方法:@Builder.ObtainVia(method = “calculateFoo”)。


builder类的名称为FoobarBuilder,其中Foobar是目标的返回类型的简化的,以标题区分大小写的形式-即,@Builderon构造函数和类型的类型名称,以及@Builderon方法的返回类型的名称。。例如,如果@Builder应用于名为的类com.yoyodyne.FancyList,则构建器名称将为FancyListBuilder。如果@Builder将应用于返回的方法,void则将命名构建器VoidBuilder。


构建器的可配置方面包括:


该生成器的类名(默认:返回类型+“生成器”)

该版本()方法的名称(默认:“build”)

该生成器()方法的名称(默认:“builder”)

如果需要toBuilder()(默认值:否)

所有生成的元素的访问级别(默认值:)public。

(不推荐使用)如果您希望构建器的“ set”方法具有前缀,即Person.builder().setName(“Jane”).build()而不是前缀,Person.builder().name(“Jane”).build()则应为前缀。

用法示例,其中所有选项均从其默认值更改:

@Builder(builderClassName = “HelloWorldBuilder”, buildMethodName = “execute”, builderMethodName = “helloWorld”, toBuilder = true, access = AccessLevel.PRIVATE, setterPrefix = “set”)

想要将构建器与JSON / XML工具Jackson一起使用?我们涵盖了:检查@Jacksonized功能。

子类如何使用 @Build 注解?

  • 父类
  • image.png
  • 子类
  • image.png
  • 同时在子类和全参数的构造器使用 @Builder 注解,最终的 build() 函数只返回了空参的构造器创建的一个子类对象,因此属性“采用 builder 方式设置的 字段最终都丢失了。


如果成员被注解,则必须是构造器或方法。如果对类注解,则会生成一个private构造器,并将所有字段作为参数,就像在类上存在 @AllArgsConstructor(AccessLevel.PRIVATE) ,就好像该构造器已经存在而是用@Builder注解。


将其加到类上,相当于包含所有属性的私有构造器,且构造器加上 @Builder 注解。


参考

https://projectlombok.org/features/Builder


目录
相关文章
|
21天前
|
存储 Java 关系型数据库
高效连接之道:Java连接池原理与最佳实践
在Java开发中,数据库连接是应用与数据交互的关键环节。频繁创建和关闭连接会消耗大量资源,导致性能瓶颈。为此,Java连接池技术通过复用连接,实现高效、稳定的数据库连接管理。本文通过案例分析,深入探讨Java连接池的原理与最佳实践,包括连接池的基本操作、配置和使用方法,以及在电商应用中的具体应用示例。
40 5
|
11天前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
11天前
|
Java
Java之CountDownLatch原理浅析
本文介绍了Java并发工具类`CountDownLatch`的使用方法、原理及其与`Thread.join()`的区别。`CountDownLatch`通过构造函数接收一个整数参数作为计数器,调用`countDown`方法减少计数,`await`方法会阻塞当前线程,直到计数为零。文章还详细解析了其内部机制,包括初始化、`countDown`和`await`方法的工作原理,并给出了一个游戏加载场景的示例代码。
Java之CountDownLatch原理浅析
|
13天前
|
Java 索引 容器
Java ArrayList扩容的原理
Java 的 `ArrayList` 是基于数组实现的动态集合。初始时,`ArrayList` 底层创建一个空数组 `elementData`,并设置 `size` 为 0。当首次添加元素时,会调用 `grow` 方法将数组扩容至默认容量 10。之后每次添加元素时,如果当前数组已满,则会再次调用 `grow` 方法进行扩容。扩容规则为:首次扩容至 10,后续扩容至原数组长度的 1.5 倍或根据实际需求扩容。例如,当需要一次性添加 100 个元素时,会直接扩容至 110 而不是 15。
Java ArrayList扩容的原理
|
19天前
|
存储 Java 关系型数据库
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践,包括连接创建、分配、复用和释放等操作,并通过电商应用实例展示了如何选择合适的连接池库(如HikariCP)和配置参数,实现高效、稳定的数据库连接管理。
37 2
|
19天前
|
算法 Java 数据库连接
Java连接池技术,从基础概念出发,解析了连接池的工作原理及其重要性
本文详细介绍了Java连接池技术,从基础概念出发,解析了连接池的工作原理及其重要性。连接池通过复用数据库连接,显著提升了应用的性能和稳定性。文章还展示了使用HikariCP连接池的示例代码,帮助读者更好地理解和应用这一技术。
32 1
|
16天前
|
Java 编译器
Java进阶之标准注解
Java进阶之标准注解
28 0
|
6月前
|
安全 Java 编译器
Java其他: 什么是Java中的注解(Annotation)?
Java其他: 什么是Java中的注解(Annotation)?
80 0
|
SQL XML SpringCloudAlibaba
Java独有特性:注解(annotation)
注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。它本身并不起任何作用,可以说有它没它都不影响程序的正常运行,注解的作用在于**「注解的处理程序」**,注解处理程序通过捕获
169 0
|
6月前
|
Java 编译器 开发者
Java注解(Annotation)技术深入解析
Java注解(Annotation)技术深入解析
449 1