Spring Data JPA @Query 注解中的 SpEL 支持

1、概览 SpEL 是 Spring Expression Language(Spring 表达式语言)的缩写,它是一种强大的工具,能显著增强与 Spring 的交互,并为配置、属性设置和查询操作提供额外的抽象。 本文将带你了解如何使用该工具使自定义查询更具动态性,通过 @Query 注解,可以使用 JPQL 或原生 SQL 来定制与数据库的交互。 2、访问参数 首先先看看如何使用 SpEL 处理方法参数。 2.1、通过索引访问 通过索引访问参数并不是最佳选择,因为这可能会给代码带来难以调试的问题。尤其是当参数类型相同时。 同时,这也提供了更大的灵活性,特别是在开发阶段,当参数的名称经常发生变化时。IDE 可能无法正确处理代码和查询的更新。 JDBC 提供了 ? 占位符,可以用它来确定参数在查询中的位置。Spring 支持这一约定,并允许以如下方式来访问参数: @Modifying @Transactional @Query(value = "INSERT INTO articles (id, title, content, language) " + "VALUES (?1, ?2, ?3, ?4)", nativeQuery = true) void saveWithPositionalArguments(Long id, String title, String content, String language); 到目前为止,使用的方法与之前在 JDBC 应用中使用的方法相同。注意,在数据库中进行更改的任何查询都需要 @Modifying 和 @Transactional 注解,INSERT 就是其中之一。所有 INSERT 的示例都将使用原生查询,因为 JPQL 不支持。

Spring Profile 指南

1、概览 本文将带你了解 Spring 中的 Profile(配置文件),这是 Spring 的核心功能之一。可以把 Bean 配置在不同的 Profile,例如:dev、test、prod。然后,可以在不同的环境中激活指定的 Profile,以便只加载当前环境所需的 Bean。 2、在 Bean 上使用 @Profile 从简单的开始,看看如何使用 @Profile 注解将 Bean 映射到特定的 Profile。 该注解接受一个(或多个) Profile 名称。 考虑一个场景:有一个 Bean,它只能在开发过程中激活,不能在生产过程中部署。 用 dev Profile 注解该 Bean,它只会在开发环境中被加载到容器。在生产环境中, dev Profile 不会被激活: @Component @Profile("dev") public class DevDatasourceConfig Profile 名称也可以用 NOT 运算符作为前缀,如 !dev,以将其从 Profile 排除。 在如下示例中,只有当 dev Profile 未激活时,组件才会被激活: @Component @Profile("!dev") public class DevDatasourceConfig 3、在 XML 中声明 Profile Profile 也可以用 XML 配置。<beans> 标签有一个 profile 属性,该属性包含以逗号分隔的 Profile 值: <beans profile="dev"> <bean id="devDatasourceConfig" class="org.

在 Spring Boot 中使用 Java Record

本文将带你了解如何在 Spring Boot 应用中利用 Java Record 来提高其效率和可读性。 Java Record 是什么? Java Record 是一种专为保存不可变数据而设计的类。它们自动提供 equals()、hashCode() 和 toString() 等方法的实现,大大减少了模板代码。因此,它们非常适合在 Spring Boot 应用中创建数据传输对象(DTO)、实体和其他模型类。 Java Record 示例 举一个简单的例子,用 Java Record 来表示一个 Person。 public record Person(String name, int age) {} 在本例中,Person 是一个 Record,包含两个字段:name 和 age。Java 自动为该 Record 提供了以下内容: 一个 public 构造函数:Person(String name, int age) 属性的 public Getter 方法:name() 和 age() 实现了 equals()、hashCode() 和 toString() 方法 使用 Getter 方法 Record 的主要特点之一是提供了用于访问字段的隐式 Getter 方法。这些方法以字段本身命名。 创建 Person 实例并使用其 Getter 方法:

Spring Bean 的生命周期

“讲一讲 Spring Bean 的生命周期”,这算是一道非常经典的面试题了! 如果没有研究过 Spring 源码,单纯去背面试题,这个问题也是可以回答出来的,但是单纯的背缺乏理解,而且面试一紧张,就容易背岔了。 在前面的文章中,给大家分析了 Spring 中 Bean 的创建是在 createBean 方法中完成的。在该方法中,真正干活的实际上是 doCreateBean 方法,具体位置在 AbstractAutowireCapableBeanFactory#doCreateBean,大家在面试时候常被问到的 Spring Bean 的生命周期,实际上就是问 doCreateBean 方法的执行逻辑。 doCreateBean 方法整体上来说,干了四件事: Bean 的实例化。 Bean 属性填充。 Bean 初始化。 Bean 销毁方法注册。 这里大家注意区分 实例化 和 初始化 两个方法,实例化是指通过反射创建出来 Bean 实例的过程,而初始化则是调用一些回调函数进行 Bean 的一些预处理。 1、实例化 // Instantiate the bean. BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args); } Object bean = instanceWrapper.

Spring State Machine(状态机)入门

说起 Spring 状态机,大家很容易联想到这个状态机和设计模式中状态模式的区别是啥呢?没错,Spring 状态机就是状态模式的一种实现,在介绍 Spring 状态机之前,让我们先来看看设计模式中的状态模式。 1、状态模式 状态模式的定义如下: 状态模式(State Pattern) 是一种行为型设计模式,它允许对象在内部状态发生变化时改变其行为。在状态模式中,一个对象的行为取决于其当前状态,而且可以随时改变这个状态。状态模式将对象的状态封装在不同的状态类中,从而使代码更加清晰和易于维护。当一个对象的状态改变时,状态模式会自动更新该对象的行为,而不需要在代码中手动进行判断和处理。 通常业务系统中会存在一些拥有状态的对象,而且这些状态之间可以进行转换,并且在不同的状态下会表现出不同的行为或者不同的功能,比如交通灯控制系统中会存在红灯、绿灯和黄灯,再比如订单系统中的订单会存在已下单、待支付、待发货、待收货等状态,这些状态会通过不同的行为进行相互转换,这时候在系统设计时就可以使用状态模式。 下面是 状态模式 的类图: 可以看到状态模式主要包含三种类型的角色: 上下文(Context):封装了状态的实例,负责维护状态实例,并将请求委托给当前的状态对象。 抽象状态(State):定义了表示不同状态的接口,并封装了该状态下的行为。所有具体状态都实现这个接口。 具体状态(Concrete State):具体实现了抽象状态角色的接口,并封装了该状态下的行为。 下面是使用状态模式实现 红绿灯 状态变更的一个简单案例: 抽象状态类: /** * @description: 抽象状态类 */ public abstract class MyState { abstract void handler(); } 具体状态类 A: /** * @description: 具体状态A */ public class RedLightState extends MyState{ @Override void handler() { System.out.println("红灯停"); } } 具体状态类 B: /** * @description: 具体状态B */ public class GreenLightState extends MyState{ @Override void handler() { System.

Spring Security - 角色和权限

1、概览 本文将带你了解如何在 Spring Security 中正确地实现 角色(Role) 和 权限(Privilege)。 2、用户、角色和权限 有如下 3 个实体: User:代表用户 Role:代表用户在系统中的高级角色。每个角色都有一组低级权限。 Privilege:代表系统中较低级别的、细粒度的特权/权限。 User 如下: @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String firstName; private String lastName; private String email; private String password; private boolean enabled; private boolean tokenExpired; @ManyToMany @JoinTable( name = "users_roles", joinColumns = @JoinColumn( name = "user_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn( name = "role_id", referencedColumnName = "id")) private Collection<Role> roles; } 如上,用户包含角色和一些额外的细节,这些细节对于适当的注册机制来说是必要的。

Spring Cache 入门教程

1、缓存抽象 本文将带你了解如何使用 Spring Cache 来提高系统性能。 2、开始使用 Spring 提供的核心缓存抽象位于 spring-context 模块中。 <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.3</version> </dependency> 另外,还有一个名为 spring-context-support 的模块,它位于 spring-context 模块之上,并提供了更多由 EhCache 或 Caffeine 支持的 CacheManager。如果想使用这些模块作为缓存存储,则需要使用 spring-context-support 模块: <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>5.3.3</version> </dependency> 由于 spring-context-support 模块临时依赖于 spring-context 模块,因此 spring-context 不需要单独的依赖声明。 2.1、Spring Boot 如果是 Spring Boot 项目,可以利用 spring-boot-starter-cache Starter 来轻松添加缓存依赖项: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> <version>2.4.0</version> </dependency> 该 Starter 包含了 spring-context-support 模块。 3、启用缓存 只需在任何配置类中添加 @EnableCaching 注解,即可启用缓存功能: @Configuration @EnableCaching public class CachingConfig { @Bean public CacheManager cacheManager() { return new ConcurrentMapCacheManager("addresses"); } } 当然,也可以通过 XML 配置来启用缓存:

Spring 中的 @Autowired 注解

1、概览 从 Spring 2.5 开始,框架引入了注解驱动的依赖注入功能。该功能的主要注解是 @Autowired 。它允许 Spring 解析并注入所依赖的 Bean 到 Bean 中。 本文将带你了解如何启用自动装配以及自动装配 Bean 的各种方法,以及如何使用 @Qualifier 注解来解决 Bean 冲突以及潜在的异常情况。 2、启用 @Autowired 注解 Spring 框架支持自动依赖注入。换句话说,通过在 Spring 配置文件中声明所有 Bean 的依赖关系,Spring 容器可以自动装配依赖 Bean 之间的关系。这就是所谓的 Spring Bean 自动装配。 首先启用注解驱动注入来加载 Spring 配置(基于 Java 的配置): @Configuration @ComponentScan("com.baeldung.autowire.sample") public class AppConfig {} <context:annotation-config> 主要用于激活 Spring XML 文件中的依赖注入注解。 Spring Boot 还引入了 @SpringBootApplication 注解。这个注解相当于使用 @Configuration、@EnableAutoConfiguration 和 @ComponentScan。 在应用的 main 类中使用这个注解: @SpringBootApplication public class App { public static void main(String[] args) { SpringApplication.

Spring Cloud Config 快速入门

1、概览 Spring Cloud Config 是 Spring 用于在分布式环境下提供集中式配置的解决方案。 本文将带你了解如何设置一个基于 Git 的配置服务器(包括加密的属性值),以及如何在 REST 应用中使用它。 2、依赖 首先是配置服务器应用,包含了 spring-cloud-config-server、spring-boot-starter-security 和 spring-boot-starter-web Starter: <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> 然后是客户端应用,只需要 spring-cloud-starter-config 和 spring-boot-starter-web 模块: <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> 3、实现配置服务器 通过在 @SpringBootApplication 类上注解 @EnableConfigServer 来启用配置服务器。该注解会自动配置所有必要的组件: @SpringBootApplication @EnableConfigServer public class ConfigServer { public static void main(String[] arguments) { SpringApplication.run(ConfigServer.class, arguments); } } 还需要配置服务器的监听端口和 Git URL(提供版本控制的配置内容)。后者可以使用诸如 http、ssh 或本地文件系统上的简单文件等协议。

在 Security Filter Chain 中自定义 Filter

1、概览 本文将带你了解如何在 Spring Security Filter Chain(过滤器链)中定义一个自定义过 Filter(过滤器)。 2、创建 Filter Spring Security 默认提供了许多 Filter,这些 Filter 在大多数情况下已经足够。 当然,有时也需要在链中创建一个新的 Filter 来实现新功能。 首先,可以实现 org.springframework.web.filter.GenericFilterBean。 GenericFilterBean 是一个简单的 javax.servlet.Filter 实现,它还实现了一系列的 Aware 接口,可以感知到 Spring 容器中的一些组件。 只需实现一个方法: public class CustomFilter extends GenericFilterBean { @Override public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { chain.doFilter(request, response); } } 3、在 Security Config 中配置 Filter 可以通过 XML 或 Java 配置把 Filter 配置到 Spring Security Filter Chain 中。