教程

Spring Security Oauth 授权服务器

1、简介 OAuth 是一种描述授权过程的开放标准。它可用于授权用户访问 API。例如,REST API 可以限制只有具有适当角色的注册用户才能访问。 OAuth 授权服务器负责认证用户身份,并签发包含用户数据和适当访问策略的访问令牌(Access Token)。 本将带你了解如何使用 Spring Security OAuth 授权服务器 实现一个简单的 OAuth 应用。 我们要创建一个 CS 应用,通过 REST API 获取资源服务器上的文章列表。客户端服务和服务器服务都需要 OAuth 身份认证。 2、授权服务器实现 先来看看 OAuth 授权服务器的配置。它作为文章资源和客户端服务器的身份认证源。 2.1、依赖 首先,在 pom.xml 中添加如下依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.5.4</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> <version>2.5.4</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-oauth2-authorization-server</artifactId> <version>0.2.0</version> </dependency> 2.2、配置 在 application.yml 文件中,设置 server.port 属性来配置认证服务器的运行端口: server: port: 9000 然后,就可以开始配置 Spring Bean 了。首先,需要一个 @Configuration 类,在该类中创建一些 OAuth 特有的 Bean。 第一个是客户端服务的 Repository。在本例中,使用 RegisteredClient Builder 类创建一个客户端:

获取 Spring Boot 中的所有端点

1、概览 本文将带你了解如何获取 Spring Boot 应用中的所有 REST 端点。 2、映射端点 在 Spring Boot 应用中,通过在 Controller 类中使用 @RequestMapping 注解来暴露 REST API 端点。要获取这些端点,有三种选择:事件监听器、Spring Boot Actuator 或 SpringDoc。 3、事件监听器 在 Controller 中使用 @RestController 和 @RequestMapping 创建 REST API 服务。这些类在 Spring Application Context 中注册为 Spring Bean。因此,当 Application Context 在启动时准备就绪,就可以使用事件监听器获取端点。定义监听器有两种方法。可以实现 ApplicationListener 接口,或者使用 @EventListener 注解。 3.1、ApplicationListener 接口 在实现 ApplicationListener 时,必须定义 onApplicationEvent() 方法: @Override public void onApplicationEvent(ContextRefreshedEvent event) { ApplicationContext applicationContext = event.getApplicationContext(); RequestMappingHandlerMapping requestMappingHandlerMapping = applicationContext .getBean("requestMappingHandlerMapping", RequestMappingHandlerMapping.class); Map<RequestMappingInfo, HandlerMethod> map = requestMappingHandlerMapping .

解决 Spring 中 “not eligible for auto-proxying” 警告

1、概览 本文将带你了解出现 “not eligible for auto-proxying” 警告的原因以及如何修复它。 2、“not eligible for auto proxying” 的原因 2.1、配置示例 首先,创建一个自定义 RandomInt 注解,使用它来注解应该插入指定范围内的随机整数的字段。 @Retention(RetentionPolicy.RUNTIME) public @interface RandomInt { int min(); int max(); } 其次,创建一个简单的 Spring 组件 DataCache 类。将一个可能被使用的随机 Group 分配给缓存,例如用于支持分片。为了实现这一点,使用自定义的注解来注解该字段: @Component public class DataCache { @RandomInt(min = 2, max = 10) private int group; private String name; } 现在,来看看 RandomIntGenerator 类。它是一个 Spring 组件,用于在 RandomInt 注解注解的字段中插入随机 int 值: @Component public class RandomIntGenerator { private Random random = new Random(); private DataCache dataCache; public RandomIntGenerator(DataCache dataCache) { this.

Spring Boot Actuator 中的端点管理

1、概览 本文将带你了解如何通过 properties 文件控制 Spring Boot Actuator 端点的状态,以及如何保证端点的安全。 2、设置 为了使用 Actuator,需要在 Maven 配置中包含 spring-boot-starter-actuator: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> <version>3.1.2</version> </dependency> 此外,从 Spring Boot 2.0 开始,如果想通过 HTTP 暴露端点,就需要包含 Web Starter: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>3.1.2</version> </dependency> 3、启用和暴露端点 默认情况下,除 /shutdown 之外的所有端点都已启用,只有 /health 和 /info 被暴露。即使为应用配置了不同的 Root Context,也能在 /actuator 中找到所有端点。 这意味着,一旦在 Maven 配置中添加了相应的 Stater,就可以访问 http://localhost:8080/actuator/health 和 http://localhost:8080/actuator/info 上的 /health 和 /info 端点。 访问 http://localhost:8080/actuator,查看可用端点列表,因为 Actuator 端点已启用 HATEOS。所以,应该能看到 /health 和 /info。 {"_links":{"self":{"href":"http://localhost:8080/actuator","templated":false}, "health":{"href":"http://localhost:8080/actuator/health","templated":false}, "info":{"href":"http://localhost:8080/actuator/info","templated":false}}} 3.1、暴露所有端点 现在,修改 application.

Spring Boot 和 JSP(Java Server Pages)

1、概览 在构建 Java Web 应用时,可以使用 Java Server Pages(JSP)作为 HTML 页面模板。 Spring Boot 是一个流行的框架,可以用它来快速开发 Java Web 应用。 但是,在 Spring Boot 中使用 JSP 有一定的局限性,应该考虑用 Thymeleaf 或 FreeMarker 来替代 JSP。 2、Maven 依赖 首先来看看在 Spring Boot 中使用 JSP 需要哪些依赖。 2.1、作为独立应用运行 首先,添加 spring-boot-starter-web 依赖。 该依赖提供了使用 Spring Boot 和默认的嵌入式 Tomcat Servlet 容器来运行 Web 应用的所有核心依赖。 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.4.4</version> </dependency> 注意,使用 Undertow 作为嵌入式 Servlet 容器使用时不支持 JSP。 接下来,需要添加 tomcat-embed-jasper 依赖,以便应用能够编译和渲染 JSP 页面: <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <version>9.0.44</version> </dependency> 虽然可以手动提供上述两个依赖,但通常最好让 Spring Boot 管理这些依赖的版本,而我们只需管理 Spring Boot 版本即可。

把 Spring Bean 设置为 Null

1、概览 本文将带你了解如何把 Spring Context 中的 Bean 设置为 null。在某些情况下,这可能很有用。例如,在测试时不想提供 Mock 对象。以及,在使用一些可选功能时,可能希望避免创建实现,并直接传递 null。 2、组件设置 有几种方法可以将 Bean 设置为 null,具体取决于 Context 的配置方式,本文主要考虑 XML、注解和 Java 配置的方式。 使用一个简单的设置,包含两个类: @Component public class MainComponent { private SubComponent subComponent; public MainComponent(final SubComponent subComponent) { this.subComponent = subComponent; } public SubComponent getSubComponent() { return subComponent; } public void setSubComponent(final SubComponent subComponent) { this.subComponent = subComponent; } } 本例将演示如何在 Spring Context 中将 SubComponent 设置为 null: @Component public class SubComponent {} 3、在 XML 配置中使用占位符 在 XML 配置中,可以使用一个特殊的占位符来标识 null 值:

Spring Boot 将 JSON 中的 Long 值序列化为 String 避免精度丢失

什么是精度丢失? Java 中长整形 Long (64位)的取值范围是:-9223372036854775808 - 9223372036854775807。 在这种情况下,由于 JavaScript 的 Number 类型是 64 位浮点数,它无法精确表示超过 53 位的整数。因此,当将 Java Long 类型的值传递给 JavaScript 时,可能会发生精度丢失。 你可以在浏览器控制台运行如下代码,更直观地感受 “精度丢失” 的问题。 let val = 9223372036854775807; console.log(val); //9223372036854776000 输出的值丢失了精度 如果我们在业务中使用 Long 作为数据类型,那么就必须要考虑浏览器客户端中 Js 存在精度丢失的问题。解决这个问题最简单的办法就是 把 Java 的 Long 值,序列化为字符串传递。 Jackson 的注解支持 Spring Boot 默认使用 Jackson 作为 JSON 的序列化、反序列化框架。Jackson 提供了 @JsonSerialize 注解,该注解的 using 属性可以指定一个 JsonSerializer 的实现类,用于自定义字段的序列化方式。 Jackson 已经预定义了一个实现 ToStringSerializer,用于把指定的字段序列化为字符串。 定义一个简单的 User 对象: package cn.springdoc.demo.model; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; public class User { // 把 Long 类型的 id 序列化为 字符串 @JsonSerialize(using = ToStringSerializer.

Spring Boot 配置 TLS

1、概览 安全通信在现代应用中发挥着重要作用。客户端和服务器之间通过普通 HTTP 进行的通信并不安全。对于生产级的应用,应该在应用中通过 TLS(传输层安全)协议启用 HTTPS。 本文将带你了解如何在 Spring Boot 应用中启用 TLS。 2、TLS 协议 TLS 为客户端和服务器之间的数据传输提供保护,是 HTTPS 协议的关键组成部分。安全套接字层(SSL)和 TLS 经常被互换使用,但两者并不相同。事实上,TLS 是 SSL 的继承者。TLS 可以单向或双向实现。 2.1、单向 TLS 在单向 TLS 中,只有客户端对服务器进行验证,以确保从受信任的服务器接收数据。为实现单向 TLS,服务器会与客户端共享其公共证书。 2.2、双向 TLS 在双向 TLS 或相互 TLS(mTLS)中,客户端和服务器都要相互验证,以确保通信双方都是可信的。在实现 mTLS 时,双方要共享各自的公开证书。 3、Spring Boot 配置 TLS 3.1、生成密钥对 要启用 TLS,需要创建一对公钥/私钥。为此,可以使用 keytool 命令行工具,它默认 随 Java 发行版一起提供。 使用 keytool 生成一对密钥,并将其存储到 keystore.p12 文件中: keytool -genkeypair -alias baeldung -keyalg RSA -keysize 4096 \ -validity 3650 -dname "CN=localhost" -keypass changeit -keystore keystore.

Alibaba Sentinel 简介

1、概览 Sentinel,哨兵。顾名思义,它是微服务的强大守护者。它提供流量控制、并发限制、熔断和自适应系统保护等功能,以确保微服务的可靠性。它是一个开源组件,由阿里巴巴集团积极维护。此外,它还是 Spring Cloud Circuit Breaker 的官方组成部分。 本文将带你了解 Alibaba Sentinel 的核心功能,包括的流量控制、熔断器和自适应系统保护,以及它的注解支持和监控仪表盘。 2、功能 2.1、流量控制 Sentinel 控制随机传入请求的速度,以避免微服务超载。这可确保服务不会因流量激增而瘫痪。它支持各种流量整形策略。当每秒查询次数(QPS)过高时,这些策略会自动将流量调整为适当的形状。 这些流量整形策略包括: 直接拒绝模式(Direct Rejection Mode)- 当每秒请求数超过设定阈值时,它会自动拒绝后续的请求。 慢启动预热模式(Slow Start Warm-Up Mode) - 如果有突发的流量激增,此模式确保请求计数逐渐增加,直到达到上限为止。 2.2、熔断和降级 当一个服务同步调用另一个服务时,另一个服务有可能因某种原因宕机。在这种情况下,线程会被阻塞,因为它们一直在等待另一个服务的响应。这会导致资源耗尽,调用方服务也将无法处理更多请求。这就是所谓的级联效应,可能会导致整个微服务架构崩溃。 为了防止出现这种情况,引入了熔断器(Circuit Breaker)。它会立即阻止对其他服务的所有后续调用。在超时时间过后,一些请求会通过。如果请求成功,熔断器就会恢复正常流量。否则,超时时间将重新开始计时。 Sentinel 利用最大并发限制原理实现熔断。它通过限制并发线程的数量来减少不稳定资源的影响。 Sentinel 也会将不稳定的资源降级。当资源的响应时间过长时,对资源的所有调用都将在指定的时间窗口内被拒绝。这样可以防止调用变得非常缓慢,从而导致连锁效应。 2.3、自适应系统保护 Sentinel 会在系统负载过高时保护服务器。它使用 load1(系统负载)作为启动流量控制的指标。在以下情况下,请求将被阻止: 当前系统负载(load1) > 临界值(highestSystemLoad)。 当前并发请求(线程数) > 预计容量(最短响应时间 * 最大 QPS) 3、用法 3.1、添加 Maven 依赖 在 pom.xml 中添加 sentinel-core 依赖: <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-core</artifactId> <version>1.8.0</version> </dependency> 3.2、定义资源 使用 Sentinel API 在 try-catch 块中定义资源和相应的业务逻辑: try (Entry entry = SphU.

Spring Bean 的命名

1、概览 当有多个相同类型的实现时,需要对 Spring Bean 进行不同的命名。这是因为如果 Bean 没有唯一的名称,Spring 在注入 Bean 时会出现歧义。 通过控制 Bean 的命名,可以告诉 Spring 我们想将哪个 Bean 注入到目标对象中。 本文将带你了解 Spring Bean 命名策略,以及如何为同一类型的 Bean 赋予多个名称。 2、默认 Bean 命名策略 Spring 为创建 Bean 提供了多种注解,可以在不同的级别使用。例如,可以在 Bean 类上放置一些注解,在创建 Bean 的方法上放置另一些注解。 首先,来看看 Spring 的默认命名策略。当只指定注解而不指定任何值时,Spring 是如何命名 Bean 的? 2.1、类级注解 首先从在类级别使用的注解的默认命名策略开始。Spring 会使用类名为 Bean 命名,并将第一个字母转换为小写。 举个例子: @Service public class LoggingService { } 如上,Spring 为 LoggingService 类创建了一个 Bean,并使用 loggingService 名称进行了注册。 这种默认的命名策略适用于所有用于创建 Spring Bean 的类级别注解,例如 @Component、@Service 和 @Controller。 2.2、方法级注解 Spring 提供了 @Bean 和 @Qualifier 等注解,可用于创建 Bean 的方法。