Bootiful Spring Boot 3.4:Spring Data

工程 | Josh Long | 2024年11月24日 | ...

发布公告博客很好地突出了 Spring Data 2024.1 中的许多功能。请记住:Spring Data 是一个伞形项目,聚合了支持 Couchbase、Redis、MongoDB、JDBC、R2DBC、Neo4J、Apache Cassandra 和无数其他数据存储的模块。 它是将数据存储连接到应用程序的最简单方法。 实际上,我们可以用这里的所有新功能写一本小书!

以下是一些引起我注意的功能。

  • 一个新的 Repository fragments SPI 允许类路径上的任何任意 .jar,或者实际上是另一个包中的代码,通过 Spring.factories 服务工厂机制为 Spring Data 存储库机制贡献扩展
  • Spring Data JPA 中大大减少的查询解析开销
  • Spring Data MongoDB 中 @TimeSeries 的过期时间
  • Spring Data for Apache Cassandra 中表和用户定义类型的键空间限定
  • Spring Data Cassandra 中使用 CqlGenerator 改进的 CQL 生成
  • Spring Data Redis 中事务和管道操作中的 Jedis Lua 脚本支持
  • 使用 JedisClientConfigBuilderCustomizer 接口自定义 JedisClientConfig
  • 还有更多!

我想谈谈一个可能会改变我的事情的功能:值表达式的最终实现,这是一种花哨的说法,即可以使用 Spring 表达式语言 (SpEL) 或属性占位符解析表达式在 Spring Data 模块中参数化查询。

值表达式内容基于一个您可以在应用程序中使用的漂亮的底层 API。

package com.example.bootiful_34.data;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.env.Environment;
import org.springframework.data.expression.ValueEvaluationContext;
import org.springframework.data.expression.ValueExpressionParser;
import org.springframework.data.expression.ValueParserConfiguration;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.test.context.DynamicPropertyRegistrar;
import org.springframework.test.context.DynamicPropertyRegistry;

@SpringBootTest
@Import(ValueExpressionDynamicPropertyRegistrar.class)
class ValueExpressionTest {

	@Test
	void test(@Autowired Environment environment) {
		var configuration = (ValueParserConfiguration) SpelExpressionParser::new;
		var context = ValueEvaluationContext.of(environment, new StandardEvaluationContext());

		var parser = ValueExpressionParser.create(configuration);
		var expression = parser.parse("${message}-#{ (6 * 7) + ''}");
		var result = expression.evaluate(context);
		Assertions.assertEquals("ni hao-42", result);
	}

}

@Configuration
class ValueExpressionDynamicPropertyRegistrar implements DynamicPropertyRegistrar {

	@Override
	public void accept(DynamicPropertyRegistry registry) {
		registry.add("message", () -> "ni hao");
	}

}

在此示例中,我在测试中使用底层 ValueEvaluationContext,我在其中动态贡献了一个属性:message 和问候语 ni hao。 该测试评估一个 String,该字符串依次具有属性占位符 ${message} 和 SpEL 表达式 #{ (6 * 7) + ''},我们在其中将两个数字相乘,然后将结果表达式转换为 String。结果正如你所期望的:ni hao-42

现在您已经看到了可能性,让我们在 Spring Data JDBC 存储库的查询方法定义中检查其中一些可能性。

package com.example.bootiful_34.data;

import org.springframework.data.jdbc.repository.query.Query;
import org.springframework.data.repository.ListCrudRepository;

import java.util.Collection;

interface CustomerRepository extends ListCrudRepository<Customer, Integer> {

	@Query(" select * from #{ #tableName }")
	Collection<Customer> all();

	@Query("  select * from customer where language = :#{locale.language} ")
	Collection<Customer> findCustomersBySystemLanguage();

	// this is new! support for property placeholder resolution in queries!
	@Query("select * from customer where os = :${os.name} ")
	Collection<Customer> findCustomersHavingSameOperatingSystemAsUs();

}

第一个查询依赖于一个 SpEL 上下文,该上下文提供查询方法中引用的实体的表名(在本例中,Customer 属于 customer SQL 数据库)。

在第二个示例查询中,我们匹配通过 EvaluationContextExtension 贡献的自定义上下文。 此扩展只是在 SpEL 执行期间使用户的 Locale 可用。

💡 提示
您知道 LocaleContextHolder 吗? 它自 Spring Framework 1.2 以来就存在于 Spring 中! 它使当前用户的 Locale 对象可用。 因此,想象一下传入一个 HTTP 请求; Spring MVC 确定用户的 Locale,然后将其安装在此处。 只要您与请求在同一个线程中,您就可以随时读取它。 真棒。

package com.example.bootiful_34.data;

import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.data.spel.spi.EvaluationContextExtension;
import org.springframework.stereotype.Component;

import java.util.Locale;

@Component
class LocaleEvaluationContextExtension implements EvaluationContextExtension {

	@Override
	public String getExtensionId() {
		return "locale";
	}

	@Override
	public Locale getRootObject() {
		return LocaleContextHolder.getLocale();
	}

}

在第三个示例查询中,我们正在匹配一个系统属性 os.name,它返回用户当前的操作系统(Mac OS X,类 UnixWindows)。

获取 Spring 新闻通讯

通过 Spring 新闻通讯保持联系

订阅

保持领先

VMware 提供培训和认证,以加速您的进步。

了解更多

获得支持

Tanzu Spring 通过一个简单的订阅提供对 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区中所有即将举行的活动。

查看全部