1、简介 本文将会带你了解如何使用 Java JMS(Java Message Service)从 IBM MQ 队列读写消息。
2、设置环境 我们可以在 Docker 容器中运行 IBM MQ,以避免手动安装和配置的复杂性。
使用以下命令以基本配置运行容器:
docker run -d --name my-mq -e LICENSE=accept -e MQ_QMGR_NAME=QM1 MQ_QUEUE_NAME=QUEUE1 -p 1414:1414 -p 9443:9443 ibmcom/mq 接下来,需要在 pom.xml 文件中添加 IBM MQ 客户端:
<dependency> <groupId>com.ibm.mq</groupId> <artifactId>com.ibm.mq.allclient</artifactId> <version>9.4.0.0</version> </dependency> 3、配置 JMS Connection 首先,我们需要用 QueueConnectionFactory 建立 JMS Connection(连接),用于创建与队列管理器(Queue Manager)的连接:
public class JMSSetup { public QueueConnectionFactory createConnectionFactory() throws JMSException { MQQueueConnectionFactory factory = new MQQueueConnectionFactory(); factory.setHostName("localhost"); factory.setPort(1414); factory.setQueueManager("QM1"); factory.setChannel("SYSTEM.DEF.SVRCONN"); return factory; } } 首先创建一个 MQQueueConnectionFactory 实例,用于配置和创建与 IBM MQ 服务器的连接。我们将主机名设置为 localhost,因为 MQ 服务器是在本地 Docker 容器内运行的。暴露的映射端口为 1414。
1、概览 在使用 Hibernate 时,经常会遇到这样的情况:在将实体持久化到数据库之前,需要更改字段的值。这种情况可能是因为需要执行必要的字段转换。
本文将通过一个示例:即在执行更新和插入操作前将字段值转换为大写字母,来了解实现这一目的的不同方法。
2、实体生命周期回调 首先,定义一个简单的实体类 Student:
@Entity @Table(name = "student") public class Student { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; @Column private String name; // Getter / Setter 方法省略 } 第一种方法是 JPA 实体生命周期回调。JPA 提供了一组注解,允许我们在不同的 JPA 生命周期事件中执行一个方法,例如:
@PrePresist:在插入事件之前执行。 @PreUpdate:在更新事件之前执行。 我们在 Student 实体类中添加 changeNameToUpperCase() 方法。该方法将 name 字段改为大写。该方法通过 @PrePersist 和 @PreUpdate 进行注解,以便 JPA 在持久化和更新之前调用该方法:
@Entity @Table(name = "student") public class Student { @PrePersist @PreUpdate private void changeNameToUpperCase() { name = StringUtils.
1、概览 本文将带你了解如何在 Spring Boot 应用中使用 HttpStatusCode,重点是 3.3.3 版中引入的最新增强功能。通过这些增强功能,HttpStatusCode 已被纳入 HttpStatus 实现,从而简化了我们处理 HTTP 状态码的方式。
这些改进的主要目的是提供一种更灵活、更可靠的方法来处理标准和自定义 HTTP 状态码,使我们在处理 HTTP 响应时具有更高的灵活性和可扩展性,同时保持向后兼容性。
2、HttpStatus 枚举 在 Spring 3.3.3 之前,HTTP 状态码在 HttpStatus 中表示为枚举。这限制了自定义或非标准 HTTP 状态码的使用,因为枚举是一组固定的预定义值。
尽管 HttpStatus 类尚未被弃用,但一些返回原始 Integer 状态码的枚举和方法(如 getRawStatusCode() 和 rawStatusCode())现已被弃用。
使用 @ResponseStatus 注解来提高代码的可读性仍然是我们推荐的方法。
我们可以将 HttpStatus 与 HttpStatusCode 结合使用,以实现更灵活的 HTTP 响应管理:
@GetMapping("/exception") public ResponseEntity<String> resourceNotFound() { HttpStatus statusCode = HttpStatus.NOT_FOUND; if (statusCode.is4xxClientError()) { return new ResponseEntity<>("Resource not found", HttpStatusCode.valueOf(404)); } return new ResponseEntity<>("Resource found", HttpStatusCode.
1、概览 对应用程序进行分析可以深入了解其运行时的行为。Java 生态系统中有多种流行的分析器(Profiler),如用于通用分析的 NetBeans Profiler、JProfiler 和 VisualVM。
本文将带你了解如何以编程方式使用 NetBeans profiler API。
2、NetBeans Profiler NetBeans IDE 提供免费的分析器来分析 Java 应用。它通过 IDE 中直观的嵌入式用户界面,提供了评估 CPU 性能和内存使用情况的功能。
然而,NetBeans Profiler 还提供了可用于编程式的分析 API。这可用于 Heap Dump 的自动化分析,而不需要依赖于 UI 界面。
Heap Dump(堆转储)是一段时间内应用的内存快照。它是深入了解内存使用情况的良好指标,因为它包括内存中的实时对象、对象的类和字段以及对象之间的引用。
3、示例项目 要使用 NetBeans Profiler API,首先在 pom.xml 中添加 依赖:
<dependency> <groupId>org.netbeans.modules</groupId> <artifactId>org-netbeans-lib-profiler</artifactId> <version>RELEASE220</version> </dependency> 该依赖提供了 JavaClasses 和 Instances 等各种工具类,以帮助我们分析类、创建的实例数量和使用的内存。
接着,创建一个简单的项目并分析它的 Heap Dump:
class SolarSystem { private static final Logger LOGGER = Logger.getLogger(SolarSystem.class.getName()); private int id; private String name; private List<String> planet = new ArrayList<>(); // 构造函数 public void logSolarSystem() { LOGGER.
1、概览 本文将带你了解如何使用 Spring JDBC 框架的 JdbcTemplate 来调用存储过程。数据库存储过程类似于函数。函数支持输入参数并有返回类型,而存储过程同时支持输入和输出参数。
2、先决条件 来看看 PostgreSQL 数据库中一个简单的存储过程:
CREATE OR REPLACE PROCEDURE sum_two_numbers( IN num1 INTEGER, IN num2 INTEGER, OUT result INTEGER ) LANGUAGE plpgsql AS ' BEGIN sum_result := num1 + num2; END; '; 存储过程 sum_twoo_numbers 接收两个输入数字,并在输出参数 sum_result 中返回它们的和。一般来说,存储过程可以支持多个输入和输出参数。但在本例中,我们只考虑了一个输出参数。
3、使用 JdbcTemplate#call() 方法 来看看如何使用 JdbcTemplate#call() 方法调用数据库存储过程:
void givenStoredProc_whenCallableStatement_thenExecProcUsingJdbcTemplateCallMethod() { List<SqlParameter> procedureParams = List.of(new SqlParameter("num1", Types.INTEGER), new SqlParameter("num2", Types.NUMERIC), new SqlOutParameter("result", Types.NUMERIC) ); Map<String, Object> resultMap = jdbcTemplate.call(new CallableStatementCreator() { @Override public CallableStatement createCallableStatement(Connection con) throws SQLException { CallableStatement callableStatement = con.
1、简介 在 JPA 中,CAST 和 TREAT 是两个不同的关键字,用于操作数据类型和实体关系。本文将带你了解 CAST 和 TREAT 的区别,并通过示例来说明它们的用法。
2、JPA 中的 CAST JPA 中的 CAST 操作符主要用于 JPQL 查询中的类型转换。它允许我们显式地将一个值从一种数据类型转换为另一种数据类型。例如,可以使用 CAST 将字符串转换为整数,反之亦然。
CAST 的语法如下:
CAST(expression AS type) expression 是我们要转换的值或字段,type 是我们要将表达式转换为的目标数据类型。
3、JPA 中的 TREAT 相比之下,TREAT 操作符是为在 JPQL 查询中对实体进行类型安全的向下转换而设计的。它在处理继承层次结构时特别有用。使用 TREAT 时,我们指定实体的子类型,然后 JPA 会检查实际实体是否确实属于该类型。
与 CAST 不同,TREAT 不会改变值的底层数据类型。相反,它允许我们像访问目标类型的值一样访问该值。
TREAT 的语法如下:
TREAT(expression AS type) expression 是要处理的值,type 是目标数据类型。
4、适用场景和用法 在 JPA 查询中,CAST 和 TREAT 都用于处理类型转换,但它们的用途不同。
4.1、CAST 操作符 CAST 用于将一种数据类型转换为另一种数据类型,以便进行操作或比较。在执行查询时,如果需要的数据类型与数据库中存储的数据类型不同,通常会使用 CAST。
示例如下:一个名为 Employee 的实体,其 salary 字段在数据库中存储为字符串。下面是 Employee 实体的定义:
1、概览 本文将带你了解 Spring Reactive 中的 switchIfEmpty() 操作符及其在使用和不使用 defer() 操作符时的行为,了解这些操作符在不同场景中的交互方式,并通过实际示例来说明它们对响应式流(Reactive Stream)的影响。
2、switchIfEmpty() 和 Defer() 的使用 switchIfEmpty() 是 Mono 和 Flux 中的一个操作符,用于在源生产者为空时执行备用生产者流。如果主源 Publisher 没有发布数据,该操作符就会切换到替代源的数据发布。
考虑一个从大型文件中通过 ID 检索用户详细信息的场景。当请求文件中的用户详细信息时,遍历文件会消耗大量时间。因此,对于经常访问的 ID,将其详细信息缓存起来更有意义。
当端点收到请求时,首先搜索缓存。如果用户详细信息可用,返回响应。如果没有,则从文件中获取数据并缓存起来,以备后续请求。
在这种情况下,主数据提供者(Primary Data Provider)是检查缓存中 KEY 是否存在的流,而备用数据提供者是检查文件中的 KEY 并更新缓存的流。switchIfEmpty() 操作符可以根据缓存中数据的可用性高效地切换数据源提供者。
了解 defer() 操作符的使用也很重要,它可以推迟函数的求值,直到发生订阅。如果我们不在 switchIfEmpty() 中使用 defer() 操作符,表达式就会立即(急切地)求值,从而可能导致意想不到的副作用。
3、示例设置 通过示例来了解 switchIfEmpty() 操作符在不同情况下的行为。
3.1、Data Model 首先,定义一个 User 模型类,其中包含一些详细信息,如 id、email、username 和 roles:
public class User { @JsonProperty("id") private String id; @JsonProperty("email") private String email; @JsonProperty("username") private String username; @JsonProperty("roles") private String roles; // Getter / Setter 省略 } 3.
1、简介 本文将会带你了解如何使用 WebClient 执行同步请求。
在响应式编程日益普及的同时,在哪些情况下这种阻塞式请求仍然是适当和必要的?
2、Spring 中的 HTTP 客户端库概述 首先,回顾一下目前可用的客户端库。
在 Spring Framework 3.0 中引入 RestTemplate 时,其简单的 HTTP 请求模板方法 API 广受欢迎。然而,其同步性质和许多重载方法在高流量应用程序中导致了复杂性和性能瓶颈。
在 Spring 5.0 中,WebClient 被引入作为一种更高效、响应式的选择,用于非阻塞请求。尽管它是 Reactive Stack Web 框架的一部分,但它支持用于同步和异步通信的 Fluent 风格的 API。
在 Spring Framework 6.1 中,RestClient 提供了另一种执行 REST 调用的选项。它将 WebClient 的 Fluent API 与 RestTemplate 的基础设施结合在一起,包括消息转换器、请求工厂和拦截器。
尽管 RestClient 针对同步请求进行了优化,但如果我们的应用还需要异步或流式传输功能,则 WebClient 更为适用。通过在阻塞和非阻塞 API 调用中使用 WebClient,我们可以保持代码库的一致性,避免混用不同的客户端库。
3、阻塞与非阻塞 API 调用 在介绍各种 HTTP 客户端时,我们使用了同步和异步、阻塞和非阻塞等术语。这些术语与上下文有关,有时可能代表同一概念的不同名称。
在方法调用方面,WebClient 根据发送和接收 HTTP 请求和响应的方式,支持同步和异步交互。如果 WebClient 等待前一个请求完成后才继续处理后一个请求,则是以阻塞方式进行的,而结果是同步返回的。
另一方面,我们可以通过执行立即返回的非阻塞调用来实现异步交互。在等待另一个系统的响应时,其他处理工作可以继续进行,一旦准备就绪,就会以异步方式提供结果。
4、什么情况下使用同步请求 如前所述,WebClient 是 Spring Webflux 框架的一部分,默认情况下一切都是响应式的。不过,该库提供异步和同步操作支持,因此适用于响应式和 Servlet Stack Web 应用。
1、概览 Gradle 是一款构建自动化工具,用于管理和自动化应用程序的构建、测试和部署过程。
使用基于 Groovy 或 Kotlin 的 DSL(Domain-Specific Language)来定义构建任务,可以轻松地自动定义和管理项目中所需的依赖。
本文将带你了解在 Gradle 中排除传递依赖的几种方法。
2、传递依赖是什么? 假设我们使用的 A 依赖于另一个库 B。默认情况下,当我们包含 A 时,Gradle 会自动将 B 添加到项目的 classpath 中,这样,即使我们没有明确地将 B 添加为依赖,也可以在项目中使用 B 的代码。
来看一个实际的例子,在项目中定义 Google Guava 依赖:
dependencies { // ... implementation 'com.google.guava:guava:31.1-jre' } 如果 Google Guava 与其他库存在依赖关系,那么 Gradle 会自动包含这些其他库。
要查看项目中使用的依赖项,可以使用如下命令将其打印出来:
./gradlew <module-name>:dependencies 假设我们的模块名为 excluding-transitive-dependencies:
./gradlew excluding-transitive-dependencies:dependencies 输出如下:
testRuntimeClasspath - Runtime classpath of source set 'test'. \--- com.google.guava:guava:31.1-jre +--- com.google.guava:failureaccess:1.0.1 +--- com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava +--- com.google.code.findbugs:jsr305:3.0.2 +--- org.
1、概览 Spring Data JPA 中的 @DynamicInsert 注解通过在 SQL 语句中只包含非 null 字段来优化插入操作。这一过程加快了结果查询的速度,减少了不必要的数据库交互。
虽然它提高了对具有许多可为空字段的实体的效率,但也引入了一些运行时开销。因此,在只有在排除空列的好处超过性能成本的情况下,有选择地使用它。
2、JPA 中 INSERT 的默认行为 使用 EntityManager 或 Spring Data JPA 的 save() 方法持久化 JPA 实体时,Hibernate 会生成一条 SQL 插入(INSERT)语句。该语句包括每个实体列,即使某些列包含 null 值。因此,在处理包含许多可选字段的大型实体时,插入操作的效率会很低。
先来看一个简单的 Account 实体:
@Entity public class Account { @Id private int id; @Column private String name; @Column private String type; @Column private boolean active; @Column private String description; // Getter / Setter } 为 Account 实体创建 JPA Repository: