1、简介 本文将带你了解 @EnableEurekaClient 与 @EnableDiscoveryClient 的区别。
这俩注解在 Spring Cloud 微服务应用中,都用于客户端发现。
2、微服务中的服务注册 在以分布式和松散耦合为特点的微服务领域,随着服务数量的增加,维护准确的服务列表并确保它们之间的无缝通信变得越来越复杂。手动跟踪服务的健康状况和可用性是一项资源密集且容易出错的工作。这时,服务注册中心就变得非常有用。
服务注册中心是一个保存可用服务信息的数据库。它是服务注册、查询和管理的中心点。
当微服务启动时,它会在服务注册中心中注册自己。
3、@EnableDiscoveryClient 注解 @EnableDiscoveryClient 是 Spring Boot 提供的一种更通用的注解,使其成为服务发现的灵活选择。
可以将其视为一种约定,它允许我们的应用现在和将来与不同的服务注册中心协同工作。它包含在 spring-cloud-commons 依赖中,成为 Spring Cloud 服务发现机制的核心部分。
但是,它并不能独立工作,实际运行时需要真正的实现,如 Eureka、Consul 或 Zookeeper。
4、@EnableEurekaClient 注解 Eureka 最初由 Netflix 开发,提供了一个强大的服务发现解决方案。Eureka 客户端是 Eureka 的基本组成部分。
具体来说,应用可以作为客户端,在使用 Eureka 实现的服务注册中心注册。此外,Spring Cloud 还为其提供了一个抽象层,与 Spring Boot 结合使用,可大大简化 Eureka 与微服务架构的集成,从而提高开发人员的工作效率。
@EnableEurekaClient 注解在这一过程中起着至关重要的作用。更确切地说,它是作为客户端的服务向服务注册中心注册时使用的注解之一。
4.1、实现 Eureka Client 只有当 pom.xml 中包含 Eureka 客户端依赖 时,Eureka 客户端才能工作:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> 还要定义 spring-cloud-commons <dependencyManagement>:
<dependencyManagement> <dependencies> <dependency> <groupId>org.
功能特点 简化多表操作:MyBatis-Plus-Join 是 MyBatis-Plus 的扩展,让开发者能更便捷地进行多表关联查询、子查询等操作,通过简洁的API满足复杂查询需求。例如,在进行多表联合查询时,无需编写大量复杂的SQL语句或配置文件,只需简单配置和调用相关方法,即可实现多表数据的关联查询。 支持多种特性:支持列枚举、别名、逻辑删除、TypeHandle、一对一、一对多等功能,还支持 Lambda 和字符串两种查询方式,以及自定义字段映射和结果转换、动态条件构造和链式调用等高级特性。比如,在进行数据查询时,可以根据不同的条件动态构造查询语句,灵活地实现各种复杂的查询逻辑。 兼容性好:作为 MyBatis-Plus 的插件,它完全兼容 MyBatis-Plus 的使用习惯,引入后不会对现有工程产生影响,能与 MyBatis-Plus 原有功能无缝集成。 依赖配置 以Maven项目为例,在pom.xml文件中添加以下依赖即可使用:
<dependency> <groupId>com.github.yulichang</groupId> <artifactId>mybatis-plus-join-boot-starter</artifactId> <version>1.5.3</version> </dependency> 最新版 MyBatis-Plus-Join 需要配合 MyBatis-Plus 3.1.2 及以上的版本使用。
代码示例 假设存在用户表 user 和订单表 order,它们之间通过 user_id 关联,以下是使用 mybatis-plus-join-boot-starter 进行多表查询的示例:
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.github.yulichang.base.MPJBaseMapper; import com.github.yulichang.wrapper.MPJLambdaWrapper; import com.example.demo.entity.User; import com.example.demo.entity.Order; import org.springframework.stereotype.Repository; import javax.annotation.Resource; import java.util.List; @Repository public class UserRepository { @Resource private MPJBaseMapper<User> userMapper; public List<User> getUserWithOrders() { // 使用MPJLambdaWrapper进行多表查询 MPJLambdaWrapper<User> wrapper = new MPJLambdaWrapper<User>() .
1、简介 WebClient 是 Spring WebFlux 中的一个 HTTP 客户端工具类,可以实现同步和异步 HTTP 请求。
本文将带你了解在 Spring WebClient 中设置 Header 的几种方式。
2、WebClient 如何处理 Header? 一般来说,HTTP 请求中的 Header 起到元数据的作用。它们包含认证详细信息、内容类型、版本等信息。
在 WebClient 中,HttpHeaders 类负责管理 Header。这是一个 Spring 框架类,专门用于表示请求和响应头。该类实现了 MultiValueMap<String, String>,允许一个 Header Key 有多个 Value。
这为需要多个值的 Header(如 Accept)提供了灵活性。
3、在 WebClient 中设置 Header 有几种方法可以为请求添加 Header。根据使用情况,我们可以为单个请求设置 Header,为整个 WebClient 实例定义全局 Header,或动态修改 Header。
3.1、为单个请求设置 Header 如果 Header 是针对单个请求的,并且因端点而异,那么直接的方法就是在请求中直接设置它们。
一个简单的示例如下。例化 WebClient,在请求中添加了两个 Header,并断言这些 Header 已通过请求发送。使用 okhttp3 库中的 MockWebServer 来模拟服务器响应并验证 WebClient 的行为:
@Test public void givenRequestWithHeaders_whenSendingRequest_thenAssertHeadersAreSent() throws Exception { mockWebServer.
1、概览 默认情况下,Spring Boot 提供嵌入式 Tomcat 服务器,但在某些情况下,我们可能希望根据应用的需求来禁用/启用它。
对于不需要 Web 服务的 Spring Boot 应用,禁用 Tomcat 可以节省资源。
2、理解 Spring Boot 中的嵌入式 Tomcat Spring Boot 在应用的可执行 JAR 文件中捆绑了嵌入式 Tomcat 服务器,从而简化了应用的部署。这种方法消除了安装和配置外部 Tomcat 实例的需要,使开发和部署更加高效。
Spring Boot 使用 Spring Boot Starter 来包含嵌入式 Tomcat 的必要依赖。默认情况下, spring-boot-starter-web Starter 会在 Tomcat 出现在 classpath 中时自动配置和初始化 Tomcat。
2.1、嵌入式 Tomcat 的优势 Spring Boot 的嵌入式 Tomcat 服务器具有多种优势:
简化部署:无需安装外部 Tomcat 服务器。 独立的应用:应用程序可打包为 JAR 文件,在任何地方运行。 自动配置:Spring Boot 根据依赖自动配置 Tomcat。 灵活:可轻松替换为 Jetty 或 Undertow 等其他嵌入式服务器。 2.2、为什么要禁用 Tomcat 服务器? 虽然嵌入式 Tomcat 很有用,但在某些情况下,禁用它对我们也有好处:
1、概览 在 Java 中使用 java.time 包处理日期和时间非常高效,但有时我们可能会遇到 DateTimeParseException 异常,提示 “Unable to obtain LocalDateTime from TemporalAccessor(无法从 TemporalAccessor 获取 LocalDateTime)”。出现这种问题的原因通常是预期的日期时间格式与实际输入不兼容。
本文将带你了解出现该异常的原因以及解决办法。
2、理解异常 当 Java 的日期时间解析器无法从 TemporalAccessor(如 LocalDate、ZonedDateTime 或 OffsetDateTime)中提取有效的 LocalDateTime 对象时,就会出现 “Unable to obtain LocalDateTime from TemporalAccessor” 异常。根本原因通常是输入字符串格式不当或不完整。
LocalDateTime 需要 日期 和 时间 两个部分。如果输入字符串缺少所需的部分或不符合预期的格式,解析过程就会失败,从而产生此异常。很多人认为 Java 可以自动推断缺少的时间值,但事实并非如此。
示例如下,解析一个日期字符串为 LocalDateTime 的错误例子:
public static void main(String[] args) { String dateTimeStr = "20250327"; // 只有日期,没时间 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd"); LocalDateTime localDateTime = LocalDateTime.parse(dateTimeStr, formatter); } 执行该代码时,会出现以下异常:
java.time.format.DateTimeParseException: Text '20250327' could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor: {},ISO resolved to 2025-03-27 of type java.
1、简介 本文将带你了解 Maven 中的预定义属性。
2、Maven 预定义属性 Maven 有一些方便的内置属性,可以于简化配置。
如果需要,甚至可以直接在 pom.xml 文件中自定义它们。
这些属性也可以在任何由 Maven 资源插件的过滤功能处理的资源文件中使用,例如 application.properties 文件。在使用这些属性时,只需要将它们包装在 ${} 中。
2.1、使用示例 示例如下,使用输出目录位置属性:
<?xml version="1.0" encoding="UTF-8"?> <project> <modelVersion>4.0.0</modelVersion> <groupId>example.override.properties</groupId> <artifactId>parameter-maven-plugin</artifactId> <version>1.0-SNAPSHOT</version> <packaging>maven-plugin</packaging> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-plugin-plugin</artifactId> <version>3.2</version> <configuration> <outputDirectory>${project.build.directory}</outputDirectory> </configuration> </plugin> </plugins> </build> </project> 上面的示例展示了如何获取 ${project.build.directory} 的默认值,即 src/main/resources。
2.2、属性覆盖示例 自定义构建路径的属性:
<?xml version="1.0" encoding="UTF-8"?> <project> <modelVersion>4.0.0</modelVersion> <groupId>example.override.properties</groupId> <artifactId>parameter-maven-plugin</artifactId> <version>1.0-SNAPSHOT</version> <packaging>maven-plugin</packaging> <build> <directory>src/main/resources/custom</directory> </build> </project> 如上,通过在 <project> -> <build> -> <directory> 中指定自定义值,将 ${project.build.directory} 属性的默认值覆盖为 src/main/resources/custom。
Spring AI 1.0.0-SNAPSHOT 在构件 ID、依赖管理和自动配置方面引入了几项重要变更。
本文将带你了解这些变更并提供项目更新指南。
最显著的变更是 Spring AI Starter 构件的命名模式:
模型 starter:spring-ai-{model}-spring-boot-starter → spring-ai-starter-model-{model} 向量存储 starter:spring-ai-{store}-store-spring-boot-starter → spring-ai-starter-vector-store-{store} MCP starter:spring-ai-mcp-{type}-spring-boot-starter → spring-ai-starter-mcp-{type} 此外,你需要添加快照仓库并更新 Dependency Management (依赖管理)配置。
有两种方式可以将项目更新到 Spring AI 1.0.0-SNAPSHOT:使用 AI 工具自动更新 或 手动更新。自动方式利用 Claude Code 快速转换你的项目,而手动方式为那些喜欢直接进行更改的人提供了逐步说明。
使用 Claude Code 自动更新 对于偏好自动化方式的用户,你可以使用 Claude Code CLI 工具,通过提供的提示自动将项目升级到 1.0.0-SNAPSHOT。这种方法可以在升级多个项目或复杂代码库时节省时间并减少错误。更多详情,请参阅升级说明中的 使用 AI 自动升级 部分。
这里仅以屏幕截图的形式展示 Claude Code CLI 工具将执行的步骤。
更新 BOM 版本。
添加仓库。
更新 starter。
全部完成!
手动更新 添加快照仓库 要使用 1.0.0-SNAPSHOT 版本,你需要在构建文件(pom.xml)中添加相应的快照仓库。其中,Central Sonatype Snapshots 仓库(https://central.
1、简介 本文将带你了解如何在 Jackson 中通过 @JsonFilter、@JsonView 和 Jackson Mixin(混合) 实现动态忽略字段。
2、项目设置 添加 Jackson 库:
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.17.2</version> </dependency> 最新版本可在 此处 找到。
3、使用 @JsonFilter 第一种方法是通过 @JsonFilter 注解指定在序列化过程中使用的过滤器。
使用 @JsonFilter 对类进行注解:
@JsonFilter("publicFilter") // 指定 Filter 名称 public class UserWithFilter { private Long id; private String name; //Getter/Setter 忽略 } 然后,动态配置 ObjectMapper,并注册 PropertyFilter 来序列化除 id 之外的所有字段:
SimpleFilterProvider filterProvider = new SimpleFilterProvider(); // 注册 Filter,指定名字 filterProvider.addFilter("publicFilter", SimpleBeanPropertyFilter.serializeAllExcept("id")); ObjectMapper objectMapper = new ObjectMapper().setFilterProvider(filterProvider); 然后,使用 objectMapper 序列化 UserWithFilter 对象:
本文将带你了解如何在 Spring Boot 中使用 spring-ai 无缝接入 DeepSeek 和通义千问来构建自己的 AI 应用。
Spring & JDK 版本:
springboot 3.4.3 jdk17 1、maven依赖 <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-openai-spring-boot-starter</artifactId> </dependency> 2、application.yaml 配置 # DeepSeek 配置,完全兼容openai配置 # spring: # ai: # openai: # base-url: https://api.deepseek.com # DeepSeek的OpenAI式端点 # api-key: sk-xxxxxxxxx # chat.options: # model: deepseek-chat # 指定DeepSeek的模型名称 # 通义千问配置 spring: ai: openai: base-url: https://dashscope.aliyuncs.com/compatible-mode # 通义千问 api-key: sk-xxxxxxxxxxx chat.options: model: qwen-plus 3、Controller package org.example.springboot3ds.controller; import jakarta.annotation.PostConstruct; import jakarta.annotation.Resource; import org.
Null Safety 旨在防止空指针(NullPointerException)异常。
最初在 Spring 中引入 Null Safety 支持要追溯到 2017 年发布的 Spring Framework 5.0。2025 年,我们会继续完善这一功能,为 Java 或 Kotlin 的 Spring 开发人员带来更多附加值。
我们要解决什么问题? 举一个具体的例子,假设我们正在使用一个提供 TokenExtractor 接口的库,其定义如下:
interface TokenExtractor { /** * Extract a token from a {@link String}. * @param input the input to process * @return the extracted token */ String extractToken(String input); } 如果由于某种原因实现返回 null 值,在 token.length() 中访问 null 引用(如下所示)会导致 NullPointerException 异常,通常会在运行时产生状态码为 500 Internal Server Error 的 HTTP 响应。