京东自营 618 + 国补 iPhone 历史最低价          领 618 红包,最高25618元

使用 record 类写简洁的 Spring Boot 代码

Spring Boot 3 的最低版本要求已经是 Java 17 了,有不少的新特性可以使用。Java 16 后新增的 record 类可以用来大幅简化代码。

1. 使用 record type 作为 component

1.1 Spring 不再鼓励字段注入依赖

@Autowired式的字段注入是 Spring 应用以往常用的注入方式,但是现在 Spring 官方已经不再鼓励使用这种方式了,在其依赖注入的官方文档 甚至完全不提这种注入方式了。究其原因,主要字段注入方式造成一些问题,如:

  1. 测试麻烦,强依赖注入或者 mock 框架
  2. 字段非 final 非不可变,容易被修改导致出现难追踪的bug
  3. 允许循环依赖

1.2 构造器注入

代码冗余

然而,Spring 目前比较鼓励的构造器依赖注入代码是相对冗余的,因为需要在声明一次字段,然后在构造器又写一遍,很多 boilerplate code. 这部分也不能用 lombok 等自动生成,因为很多字段需要在构造函数的参数里指定 bean 名。如

@Component
class Dao {
    final private JdbcTemplate pgTemplate;
    final private JdbcTemplate ckTemplate;

    Dao(@Qualifier("ck1") JdbcTemplate ckTemplate,
        @Qualifier("pg2") JdbcTemplate pgTemplate) {
        this.pgTemplate = pgTemplate;
        this.ckTemplate = ckTemplate;
    }
}

1.3 record 类完美契合Java Component场景

在这种情况下,record 类就完美契合这种场景了。

  1. 声明起来非常简洁。
  2. 字段默认 final,不怕循环信赖
  3. Spring 的 Component 大部分都是单例,几乎所有的字段初始化后都没有修改值的必要
@Component
record Service(@Qualifier("ck1") JdbcTemplate ckTemplate,
           @Qualifier("pg2") JdbcTemplate pgTemplate) {}

record 类作为 Component 的问题是 record 类是 final 类,是不能有子类的,而 Spring Boot 默认使用了子类的方式实现 AOP

. 要使用 record 类需要使用 Java 内置的 interface proxy 功能,必须声明配置

spring.aop.proxy-target-class=false

详见 Spring-boot-autoconfigure

在同一个文件中写 Service 与默认实现是比较好的格式

// Service.java
interface Service {};

@Component
record SericeImpl(@Qualifier("ck1") JdbcTemplate ckTemplate,
           @Qualifier("pg2") JdbcTemplate pgTemplate
) implements Service {}

2 Spring 各种类对象声明的简化和改善

长期以来,Java 的冗长的代码风格是比较受诟病的。比如这个问题 Java中各种O(PO、DO、VO、DTO等) 是不是人为增加系统复杂度?

2.1 使用 record 作为各种O并写入各自所属的 interface 中

各种 O 不仅冗长而且都是碎片化的小类,散落各地,管理起来非常不便,放任的话项目里就充满了各种毫无意义的垃吸代码。我们可以用把 record 类写在 interface 的方式写非常简洁的代码。

PO, persistant object:持久层对象在 Dao 中

interface Dao {
	record User(String name);
}
@Component record DaoImpl() {}

VO, value object:值对象 (只负责向前台返回数据)

展开阅读全文

本文系作者在时代Java发表,未经许可,不得转载。

如有侵权,请联系nowjava@qq.com删除。

编辑于

关注时代Java

关注时代Java