Spring Initializr 是 Spring 官方提供的一个用于快速创建和初始化 Spring 项目的在线工具。它可以让开发人员选择所需的 Spring 模块、版本、语言(Java、Kotlin 或 Groovy)和构建工具(Maven 或 Gradle),并生成一个基本的项目结构。现在大多数 IDE 都对 Spring Initializr 提供了支持!
官方的 Spring Initializr 服务(start.spring.io)部署在海外,在国内访问经常出现各种连网络接失败的问题。好在 Spring Initializr 是一个开源的项目,我们可以用它来构建自己的 Spring Initializr 服务。
Spring Initializr Github 仓库:https://github.com/spring-io/start.spring.io
构建 Spring Initializr 服务 Clone 项目 需要先在机器上安装 git 软件。
git clone https://github.com/spring-io/start.spring.io.git 该仓库下有三个工程,我们只关心其中2个:
start-client 前端工程,使用 React 开发。 start-site 后端工程,是一个 Spring Boot 应用。 执行构建 项目使用 maven 构建,且提供了 mvnw(Maven Wrapper) 脚本,它是一个用于管理和运行 Maven 项目的工具。它的作用是在没有全局安装 Maven 的情况下,通过自动下载和配置特定版本的 Maven 来确保项目的构建和运行环境一致性。也就是说 不需要在本地安装 Maven,通过此脚本即可完成构建。
进入项目根目录,执行如下命令进行自动构建:
1、简介 在 Spring 中可以使用 @Cacheable 注解通过 AOP 技术地轻松为 Bean 中的方法启用缓存功能。但是,当你尝试在 Bean 的其他方法中直接调用 @Cacheable 方法时,缓存功能会失效。
本文将会解释这种情况下缓存功能失效的原因以及解决办法。
2、复现问题 首先,初始化一个启用缓存的 Spring Boot 应用。然后创建一个 MathService,其中的 square 方法注解了 @Cacheable:
@Service @CacheConfig(cacheNames = "square") public class MathService { private final AtomicInteger counter = new AtomicInteger(); @CacheEvict(allEntries = true) public AtomicInteger resetCounter() { counter.set(0); return counter; } @Cacheable(key = "#n") public double square(double n) { counter.incrementAndGet(); return n * n; } } 接着,再在 MathService 中创建一个 sumOfSquareOf2 方法,调用两次 square 方法:
1、简介 本文介绍了一些限制 WebClient 并发请求数量的方式。
2、服务端 限制 WebClient 并发请求数量是为了避免服务器因大量并发请求而宕机。有些服务自身也提供了一些限制策略。
2.1、一个简单的 Controller 为了演示,先定义一个简单的 @RestController,它返回固定范围的随机数字:
@RestController @RequestMapping("/random") public class RandomController { @GetMapping Integer getRandom() { return new Random().nextInt(50); } } 接下来,我们将模拟一些耗时的操作,并限制并发请求的数量。
2.2、服务器限制并发请求数 修改服务,模拟一个更真实的场景。
首先,限制服务器可接受的并发请求数,并在达到限制时抛出异常。
其次,增加处理响应的延迟,模拟耗时的操作。
创建 Concurrency 用于限制并发数量:
public class Concurrency { public static final int MAX_CONCURRENT = 5; static final AtomicInteger CONCURRENT_REQUESTS = new AtomicInteger(); public static int protect(IntSupplier supplier) { try { if (CONCURRENT_REQUESTS.incrementAndGet() > MAX_CONCURRENT) { throw new UnsupportedOperationException("max concurrent requests reached"); } TimeUnit.
1、概览 Groovy 是一种功能强大的动态 JVM 语言,具有众多特性。在 Spring 中使用 Groovy 可以大大提高应用程序的灵活性和可读性。从 Spring 4 开始 支持基于 Groovy 的配置。
在本教程中,我们将了解 Groovy 与 Spring 结合使用的各种方法。首先介绍了如何使用 Spring 提供的多个选项来创建 Groovy Bean 定义。接下来,了解如何使用 Groovy 脚本加载 Application Context。最后,学习如何使用 XML 和 GroovyScriptEngine 类将 Groovy 作为脚本执行(无需编译)。
2、Maven 依赖 首先,在 pom.xml 中定义 Groovy 依赖:
<dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy</artifactId> <version>3.0.12</version> </dependency> 此外,还需要添加 GMavenPlus 插件来编译 Groovy 文件:
<build> <plugins> <plugin> <groupId>org.codehaus.gmavenplus</groupId> <artifactId>gmavenplus-plugin</artifactId> <version>1.9.0</version> <executions> <execution> <goals> <goal>addSources</goal> <goal>addTestSources</goal> <goal>generateStubs</goal> <goal>compile</goal> <goal>generateTestStubs</goal> <goal>compileTests</goal> <goal>removeStubs</goal> <goal>removeTestStubs</goal> </goals> </execution> </executions> </plugin> </plugins> </build> 3、Bean 定义 传统上,开发人员通过 XML 配置来声明 Bean。这种方式后来被通过 Java 注解以编程方式定义 Bean 所取代。另一种声明 Bean 的方式是通过 Groovy 脚本。
1、概览 使用 Spring Security,可以为应用配置身份认证和授权,以控制方法(如端点)的访问权限。
在 5.6 之前,使用 @EnableGlobalMethodSecurity 注解是标准的做法,在 5.6 之后,@EnableMethodSecurity 引入了一种更灵活的方法来配置方法安全授权(Method Security)。
在本教程中,我们将通过示例代码了解 @EnableMethodSecurity 如何代替 @EnableGlobalMethodSecurity,以及他们之间的区别。
2、@EnableMethodSecurity 和 @EnableGlobalMethodSecurity 让我们来看看方法授权如何与 @EnableMethodSecurity 和 @EnableGlobalMethodSecurity 配合使用。
2.1、@EnableMethodSecurity 通过 @EnableMethodSecurity,可以看到 Spring Security 为授权类型(Authorization Type)采用基于 Bean 的配置。
我们现在为每种类型都设置了一个配置,而不是全局配置。例如,Jsr250MethodSecurityConfiguration:
@Configuration(proxyBeanMethods = false) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) class Jsr250MethodSecurityConfiguration { // ... @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) Advisor jsr250AuthorizationMethodInterceptor() { return AuthorizationManagerBeforeMethodInterceptor.jsr250(this.jsr250AuthorizationManager); } @Autowired(required = false) void setGrantedAuthorityDefaults(GrantedAuthorityDefaults grantedAuthorityDefaults) { this.jsr250AuthorizationManager.setRolePrefix(grantedAuthorityDefaults.getRolePrefix()); } } MethodInterceptor 主要包含一个 AuthorizationManager,它现在将 “检查和返回最终决策的 AuthorizationDecision 对象” 的责任委托给适当的实现,这里是 AuthenticatedAuthorizationManager。
1、概览 在本教程中,我们将了解如何在运行时重新初始化 Spring Context 中的 Singleton Bean。
默认情况下,Singleton Scope Bean 不会在应用生命周期中重新初始化。不过,有时可能需要重新创建 Bean,例如在需要更新属性时。我们将介绍几种实现此目的的方法。
2、示例 一个小示例。创建一个 Bean,从配置文件中读取属性保存在内存中。如果配置文件中的属性值被修改,那么 Bean 就要重新加载配置。
2.1、Singleton Bean 首先创建 ConfigManager 类:
@Service("ConfigManager") public class ConfigManager { private static final Log LOG = LogFactory.getLog(ConfigManager.class); private Map<String, Object> config; private final String filePath; public ConfigManager(@Value("${config.file.path}") String filePath) { this.filePath = filePath; initConfigs(); } private void initConfigs() { Properties properties = new Properties(); try { properties.load(Files.newInputStream(Paths.get(filePath))); } catch (IOException e) { LOG.error("Error loading configuration:", e); } config = new HashMap<>(); for (Map.
1、简介 在本教程中,我们将学习如何使用 WebClient 从服务器以流式下载一个大文件。我们通过创建一个简单的 Controller 和两个客户端进行演示。最后,我们将了解如何以及何时使用 Spring 的 DataBuffer 和 DataBufferUtils 工具类。
2、服务器 创建一个可以下载文件的简单 Controller。
首先,构建一个 FileSystemResource,传递一个文件路径,然后将其封装为 ResponseEntity 的 body:
@RestController @RequestMapping("/large-file") public class LargeFileController { @GetMapping ResponseEntity<Resource> get() { return ResponseEntity.ok() .body(new FileSystemResource(Paths.get("/tmp/large.dat"))); } } 其次,我们需要生成下载所用的示例文件,文件内容并不重要,所以我们使用 fallocate 在磁盘上生成一个指定大小的“空”内容文件。如下:
fallocate -l 128M /tmp/large.dat 然后就可以开始编写客户端了。
3、WebClient 使用 ExchangeStrategies 处理大文件 先用一个简单而有限的 WebClient 下载文件。使用 ExchangeStrategies 来提高 exchange() 操作的可用内存限制。这样,就能操作更多字节,但仍受限于 JVM 可用的最大内存。
使用 bodyToMono() 从服务器获取 Mono<byte[]>:
public class LimitedFileDownloadWebClient { public static long fetch(WebClient client, String destination) { Mono<byte[]> mono = client.
1、概览 我们经常遇到的一个编码问题是,URI 变量中包含一个加号(+)。例如,如果我们的 URI 变量值为 http://localhost:8080/api/v1/plus+sign,那么加号将被编码为空格,这可能会导致意外的服务器响应。
在本教程中,我们将学习如何在 Spring 的 RestTemplate 上对 URI 变量进行编码。
让我们来看看解决这个问题的几种方法。
2、项目设置 创建一个使用 RestTemplate 进行 API 调用的小项目。
2.1、Spring Web 依赖 在 pom.xml 中添加 Spring Web Starter 依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> 或者,可以使用 Spring Initializr 生成项目并添加依赖。
2.2、RestTemplate Bean 创建一个 RestTemplate Bean:
@Configuration public class RestTemplateConfig { @Bean public RestTemplate restTemplate() { return new RestTemplate(); } } 3、 调用 API 创建一个 service 类,调用公共 API http://httpbin.org/get。
API 会返回一个包含请求参数的 JSON 响应。例如,如果我们在浏览器上访问 URL https://httpbin.
⭐ 新特性 ArithmeticException:在 @Scheduled(fixedDelay = Long.MAX_VALUE, timeUnit = TimeUnit.MINUTES) 上 long 溢出 #31210 对 RequestResponseBodyMethodProcessor 中的 resolveArgument 方法进行优化 #31175 更新 BeanValidationBeanRegistrationAotProcessor 中 validation exception 的日志级别 #31147 跳过在 PathMatchingResourcePatternResolver 中搜索不存在的目录。#31111 在 Argument[Type]PreparedStatementSetter 的 doSetValue() 中为 argValue 添加 @Nullable #31086 优化 StringUtils 中的 whitespace 检查 #31067 使用 simple JPARepository 时缺少代理提示 #31050 为 ReactiveAdapterRegistry 中的现有 adapter 注册 override #31047 DefaultListableBeanFactory#getBeanNamesForType 在解析 FactoryBean 时未考虑目标类型 #30987 让 spring-core 访问 org.jboss.vfs,以便在 WildFly 上支持 VfsUtils #30973 当 contentLength 可用时,在 StringHttpMessageConverter 中使用 readNBytes #30942 当数组长度不大于 1 时,跳过数组排序 #30934 避免对每个 SseEventBuilder 条目进行刷新 #30912 使用 protected 修饰 DefaultGenerationContext(DefaultGenerationContext, String) 构造函数 #30895 在 Spring MVC 中的 AbstractResourceResolver 子类中添加缺失的 @Nullable 注解 #30893 创建 scope Bean 实例时的性能瓶颈 #30883 对同一 Bean 类中的多个 @Autowired 方法进行确定性的 Bean 初始化 #30359 优化 ClassUtils#getMostSpecificMethod #30272 Hibernate native 查询代理缺少 native 提示 #29603 检查异常原因以支持 @PropertySource(ignoreResourceNotFound) #22276 调整 PayloadMethodArgumentResolver 中的验证元数据处理方式 #21852 🐞 Bug 修复 Spring Boot 启动失败 does not reside in the file system: manifoldclass://622488023/.
1、概览 本文将会带你学习在 Spring 应用中实现 Kafka Consumer 重试消费的 2 种方式,及其优缺点。
关于如何在 Spring 中整合 Kafka 的细节,请参阅 这里。
2、项目设置 创建一个新的 Spring Boot 项目,并添加 spring-kafka 依赖:
<dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> <version>3.0.1</version> </dependency> 创建一个对象:
public class Greeting { private String msg; private String name; // 构造函数、get、set 方法省略 } 3、Kafka Consumer Kafka Consumer(消费者)是从 Kafka 集群中读取数据的客户端应用程序。它订阅一个或多个 topic,并消费已发布的消息。Producer (生产者)向 topic 发送消息,topic 是存储和发布记录的类别名称。topic 被分为多个分区,以便横向扩展。每个分区都是一个不可更改的消息序列。
Consumer 可以通过指定偏移量(即消息在分区中的位置)来读取特定分区中的消息。Ack(确认)是消费者发送给 Kafka broker 的消息,表示它已成功处理了一条记录。一旦 ACK 被发送,消费者偏移量(consumer offset)将会被更新。
这将确保消息已被消费,并且不会再次传递给当前 Listener。
3.1、Ack 模式 Ack 模式决定了 broker 何时更新消费者偏移量(consumer offset)。