1、概览 本文将会带你了解 Spring 中的 @AliasFor 注解。
首先介绍一些框架中的使用示例,最后看看如何在自定义注解中使用 @AliasFor。
2、注解 @AliasFor 自 4.2 版起成为框架的一部分。多个 Spring 核心注解已更新为包含此注解。
可以将其用于装饰单个注解中的属性,或者在由元注解组成的注解中使用。元注解是可以应用于其他注解的注解。
在同一个注解中,使用 @AliasFor 来声明属性的别名,这样就可以交替使用它们。或者,可以在组合注解中使用 @AliasFor 来覆盖元注解中的属性。换句话说,当使用 @AliasFor 在组合注解中装饰属性时,它会覆盖其元注解中的指定属性。
许多核心 Spring 注解,如 @Bean、@ComponentScan、@Scope、@RequestMapping 和 @RestController 现在都使用 @AliasFor 来配置其内部属性别名。
@AliasFor 注解的定义如下:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Documented public @interface AliasFor { @AliasFor("attribute") String value() default ""; @AliasFor("value") String attribute() default ""; Class<? extends Annotation> annotation() default Annotation.class; } 既可以隐式地使用这个注解,也可以显式地使用它。隐式使用仅限于注解内部的别名。相比之下,显式使用还可以用于元注解中的属性。
3、注解中的显示别名 参考 Spring 的核心注解 @ComponentScan:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Repeatable(ComponentScans.class) public @interface ComponentScan { @AliasFor("basePackages") String[] value() default {}; @AliasFor("value") String[] basePackages() default {}; .
1、简介 本文将带你了解 Spring 中的 @Conditional 注解。它用于根据特定条件来控制 Bean 的创建和注册。
2、声明条件 首先来看看在哪些情况下可以使用条件注解。
最常见的用法是包含或排除整个配置类:
@Configuration @Conditional(IsDevEnvCondition.class) class DevEnvLoggingConfiguration { } 或者是一个 Bean:
@Configuration class DevEnvLoggingConfiguration { @Bean @Conditional(IsDevEnvCondition.class) LoggingService loggingService() { return new LoggingService(); } } 如上,这样就可以根据特定条件(如环境类型或特定需求)来调整应用的行为。在上例中,只为开发环境初始化了额外的 LoggingService。
另一种方式是直接在组件类上放置条件。
@Service @Conditional(IsDevEnvCondition.class) class LoggingService { // ... } 可以将上述示例应用于任何使用 @Component、@Service、@Repository 或 @Controller 注解声明的 Bean。
3、预定义条件注解 Spring 自带一组预定义的条件注解。
首先,看看如何根据配置的属性值来创建组件:
@Service @ConditionalOnProperty( value="logging.enabled", havingValue = "true", matchIfMissing = true) class LoggingService { // ... } 第一个属性 value 指定了要匹配的配置属性。第二个属性 havingValue 定义了该条件所需的值。最后,matchIfMissing 属性告诉 Spring,如果参数缺失,是否应匹配该条件。
1、概览 本文将带你了解如何在 Spring 应用的 Service 层中使用 Spring Validation 进行校验。
2、应用分层 Spring Web 应用通常分为如下几层:
Consumer 层或 Web 层是 Web 应用程序的最上层。它负责解析用户的输入并提供适当的响应。其他层抛出的异常也必须由 Web 层处理。由于 Web 层是应用程序的入口点,因此它负责身份认证,是防止未授权用户的第一道防线。
在 Web 层之下是 Service 层。它充当事务屏障,同时承载应用和基础设施服务。Service 层的公共 API 由应用服务提供。它们通常作为事务边界,并负责授权事务。基础设施服务提供与外部工具(包括文件系统、数据库和电子邮件服务器)连接的 “管道代码”。这些方法通常被多个应用服务使用。
Web 应用的最底层是持久层。换句话说,它负责与数据存储进行交互。
3、Service 层的验证 Service 层是应用中的一个层,用于在 Controller 和持久层之间进行通信。此外,业务逻辑也存储在 Service 层中。其中特别包括验证逻辑。Model 状态用于 Controller 层和 Service 层之间的通信。
在业务层进行验证逻辑有其优点和缺点。Spring 的验证(和数据绑定)架构并不排除任何一种方式。验证未绑定在 Web 层,这易于本地化,并且允许使用任何可用的 Validator。
此外,客户端输入数据并不总是通过 REST Controller 处理,如果不在 Service 层进行验证,非法数据可能会通过,引发多个问题。
在这种情况下,可以使用标准的 Java JSR-303 验证方案。
4、示例 使用 Spring Boot 开发一个简单的用户注册应用。
4.1、Domain 只有 name、age、phone 和 password 属性:
1、简介 Content Type 表示请求/响应数据的媒体类型(Media Type)。当 Conroller 收到 Web 请求时,它会根据 Content Type 解析请求数据,然后根据 Content Type 响应数据。目前在 REST 中最流行的 Content Type 就是 JSON。
本文将会带你了解如何在 Spring MVC 中设置请求和响应的 Content Type。
2、@RequestMapping 注解 简而言之,@RequestMapping 是将 Web 请求映射到 Spring Controller 的重要注解。它有各种属性,包括 HTTP 方法、请求参数、Header 和媒体类型。
一般来说,媒体类型分为两类:消费(请求)、生产(响应)。也可以在 Spring 中定义自定义媒体类型。
其目的在于限制 Handler 可消费、生产的媒体类型。
2.1、请求的媒体类型 通过 consumes 属性指定 Controller 可接受的媒体类型,可以有多个。
定义一个简单的端点:
@RequestMapping(value = "/greetings", method = RequestMethod.POST, consumes="application/json") public void addGreeting(@RequestBody ContentType type, Model model) { } 如果 Controller 不支持客户端指定的媒体类型,则会返回 HTTP “415 Unsupported Media Type” 错误。
1、简介 DispatcherServlet 在 Spring 应用中扮演着重要角色,它为应用提供了一个入口点。Context Path 定义了终端用户访问应用的 URL。
本文将带你了解 Spring 中 Context Path(上下文路径)与 Servlet Path(Servlet 路径)的区别。
2、Context Path 简而言之,Context Path 是访问 Web 应用时使用的名称。它是应用的根路径。默认情况下,Spring Boot 在 ROOT 上下文路径("/")上提供服务。
因此,默认情况下,Spring Boot 应用可以通过 http://localhost:8080/ 访问。
不过,在某些情况下,我们可能需要更改应用的 Context。配置 Context Path 有多种方法,最简单的方式就是通过位于 src/main/resources 文件夹下的 application.properties 进行配置。
server.servlet.context-path=/demo 如上,此时应用的主页为:
http://localhost:8080/demo 特别是在把应用部署到外部服务器时,往往需要修改应用的 Context Path,以便于其他一起部署的应用分开来。
3、Servlet Path Servlet Path 表示 DispatcherServlet 的 Path。DispatcherServlet 是一个实际的 Servlet,继承自 HttpSerlvet 。默认值与 Context Path 类似,即(“/”):
spring.mvc.servlet.path=/ 在 Boot 的早期版本中,该属性位于 ServerProperties 类中,名称为 server.servlet-path=/。
从 2.
1、概览 文件上传是现在应用中很常见的需求,从 Spring 5 开始可以通过响应式上传文件。有了响应式编程的加持,能够使用较少的线程和背压(Backpressure)机制,以非阻塞的方式进行上传。
本文将带你了解使用 WebClient(一种非阻塞、响应式的 HTTP 客户端)通过 BodyInserters 上传文件的两种不同方法。WebClient 是名为 Project Reactor 的响应式编程库的一部分。
2、使用 WebClient 上传文件 首先,在项目中添加 spring-boot-starter-webflux 依赖:
<dependency> <groupId>org.springframework.boot</groupId>. <artifactId>spring-boot-starter-webflux</artifactId> </dependency> 2.1、上传单个文件 首先,声明上传地址的 URL:
URI url = UriComponentsBuilder.fromHttpUrl(EXTERNAL_UPLOAD_URL).build().toUri(); 比方说,在本例中要上传 PDF。因此使用 MediaType.APPLICATION_PDF 作为 ContentType。上传端点会返回一个 HttpStatus。由于只希望得到一个结果,所以将其封装在一个 Mono 中:
Mono<HttpStatus> httpStatusMono = webClient.post() .uri(url) .contentType(MediaType.APPLICATION_PDF) .body(BodyInserters.fromResource(resource)) .exchangeToMono(response -> { if (response.statusCode().equals(HttpStatus.OK)) { return response.bodyToMono(HttpStatus.class).thenReturn(response.statusCode()); } else { throw new ServiceException("Error uploading file"); } }); 调用这个方法的方法也可以返回一个 Mono,可以一直进行下去,直到真正需要访问结果为止。就绪后,可以在 Mono 对象上调用 block() 方法。
1、简介 所有 Java Web 框架都建立在 Servlet Api 的基础之上。在基于 Spring 开发的 Java Web 应用中,有三个文件起着至关重要的作用。通常,按以下顺序将它们串联起来:web.xml -> applicationContext.xml -> spring-servlet.xml。
本文将带你了解 applicationContext.xml 和 spring-servlet.xml 之间的区别。
2、applicationContext.xml 反转控制(IoC)是 Spring 的核心。在使用 IoC 的框架中,通常由容器负责实例化、创建和删除对象。在 Spring 中,applicationContext 就扮演着 IoC 容器的角色。
在开发标准 J2EE 应用时,会在 web.xml 文件中声明 ContextLoaderListener。此外,还定义了一个 contextConfigLocation 来指定 XML 配置文件。
<context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/applicationContext*.xml</param-value> </context-param> 应用启动时,Spring 会加载该配置文件,并使用它创建 WebApplicationContext 对象。如果没有 contextConfigLocation,默认情况下,系统将查找 /WEB-INF/applicationContext.xml 来加载。
简而言之,applicationContext 是 Spring 的核心接口。它为应用提供配置信息。
在该文件中,提供了与应用相关的配置。通常,这些配置包括基本数据源、属性占位符文件(Property Place Holder)和用于项目本地化的消息源(Message Source),以及其他增强功能。
示例如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:c="http://www.springframework.org/schema/c" xmlns:p="http://www.
简介 本文将带你了解如何使用 Spring 和 Hibernate 实现表分区。
表分区的目标是将一个大型表分割为多个较小的分区表,以便关联的表和索引记录可以放入内存缓冲池,从而实现更高效的查找或扫描操作。
使用 PostgreSQL 进行表分区 PostgreSQL 为 表分区 提供了三种策略:
列表分区(List Partitioning) 范围分区(Range Partitioning) Hash 分区(Hash Partitioning) 本例使用列表分区,按大洲来划分数据表。
例如,users 分区如下:
CREATE TABLE users ( id bigint NOT NULL, first_name varchar(255), last_name varchar(255), registered_on timestamp(6), partition_key varchar(255), PRIMARY KEY (id, partition_key) ) PARTITION BY LIST (partition_key) CREATE TABLE users_asia PARTITION OF users FOR VALUES IN ('Asia') CREATE TABLE users_africa PARTITION OF users FOR VALUES IN ('Africa') CREATE TABLE users_north_america PARTITION OF users FOR VALUES IN ('North America') CREATE TABLE users_south_america PARTITION OF users FOR VALUES IN ('South America') CREATE TABLE users_europe PARTITION OF users FOR VALUES IN ('Europe') CREATE TABLE users_australia PARTITION OF users FOR VALUES IN ('Australia') posts 表分区如下:
1、简介 本文将带你了解一个相对较新的 Spring Boot 条件注解 @ConditionalOnThreading。
2、条件注解 条件注解提供了一种仅在满足各种特定条件时才在 BeanFactory 中注册 Bean 的方法。开发人员通过使用 Condition 接口为每个注解单独定义这些条件。
Spring Boot 为常见用例提供了大量预定义的条件注解。常见的示例有 @ConditionalOnProperty、@ConditionalOnBean 和 @ConditionalOnClass。
3、@ConditionalOnThreading 原理 @ConditionalOnThreading 只是 Spring Boot 中另一个预定义的条件注解。它是在 3.2 版本中添加的,在本文撰稿时,该版本本身还是候选发布版。也就是说,需要使用专用的 Spring Artifacts 仓库。
<repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> <repository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <releases> <enabled>false</enabled> </releases> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> <pluginRepository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <releases> <enabled>false</enabled> </releases> </pluginRepository> </pluginRepositories> @ConditionalOnThreading 注解仅允许在 Spring 内部配置为使用特定类型的线程时创建 Bean。所谓线程类型,是指平台线程或虚拟线程。回顾一下,从 Java 21 开始,我们就可以 使用虚拟线程来代替平台线程 了。
1、概览 在 Web 应用中,我们通常需要通过 spring-validation 对客户端提交的数据进行校验。如果校验失败则会抛出异常。默认情况下,关于校验失败细节的异常信息是英文。本文将会带你了解如何对校验失败时的异常消息进行国际化(也称为“本地化”)。
2、依赖 首先在 pom.xml 中添加 Spring Boot Starter Web 和 Spring Boot Starter Validation:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> 最新版本可在 Maven Central 上找到。
3、本地化信息存储 在 Java 应用中,通常使用 properties 文件存储本地化信息。一般称为 Resource Bundle。
这些文件是由键值对组成的纯文本文件。key 是信息检索的标识符,而对应的 value 则是相应语言的本地化消息。
接下来,我们创建 2 个 properties 文件。
CustomValidationMessages.properties 是默认的 properties 文件,文件名不包含任何语言名称。只要客户端指定的语言不支持,应用就会使用默认语言:
field.personalEmail=Personal Email validation.notEmpty={field} cannot be empty validation.email.notEmpty=Email cannot be empty 再创建一个额外的中文语言的 properties 文件 - CustomValidationMessages_zh.properties。只要客户端指定 zh 或 zh-tw 等变体作为本地语言,应用语言就会切换为中文: