二==---=---SW0000P=二
spring.swagger2.enabled=true
#在springboot2.6.X结合swagger2.9.X会提示documentationPluginsBootstrapper空指针异常#原因是在springboot2.6.X中将SpringMVC默认路径匹配策略从AntPathMatcher更改为PathPatternParser,#号致出错,解决办法是atching-strategy切换回之ant pathmatcherspring.mvc.pathmatch.matching-strategy=ant path matcher
这一段讲了个啥
这段文字主要讲了在Spring Boot 2.6.X版本结合Swagger 2.9.X版本时可能会遇到一个空指针异常的问题。具体来说:
问题描述:
在Spring Boot 2.6.X版本中,Spring MVC默认的路径匹配策略从AntPathMatcher更改为了PathPatternParser。
这种更改会导致在使用Swagger 2.9.X时出现documentationPluginsBootstrapper空指针异常。
解决办法:
将Spring MVC的路径匹配策略切换回AntPathMatcher。
具体操作是在配置文件中添加一行配置:spring.mvc.pathmatch.matching-strategy=ant_path_matcher。
通过这种方式,可以解决由于路径匹配策略更改而导致的Swagger与Spring Boot不兼容的问题。
===============
为什么要用ThreadLocalRandom
在多线程环境中使用 `ThreadLocalRandom` 而不是 `java.util.Random` 具有以下几个优势:
1. **性能优势**:
- `ThreadLocalRandom` 是专门为多线程环境设计的。它避免了在多个线程之间共享 `Random` 实例时所需的同步开销,从而提高了性能。
- 每个线程都有自己的 `ThreadLocalRandom` 实例,这意味着不同线程之间不会相互干扰,减少了竞争。
2. **简化代码**:
- 使用 `ThreadLocalRandom` 可以避免显式地创建和管理 `Random` 实例。
- 代码简洁,直接调用 `ThreadLocalRandom.current()` 即可获取当前线程的 `ThreadLocalRandom` 实例。
3. **减少资源争用**:
- 在高并发环境中,多个线程共享一个 `Random` 实例会导致竞争,进而影响性能。`ThreadLocalRandom` 通过为每个线程提供独立的实例,避免了这种资源争用。
具体到你的代码:
```java
int keyId = ThreadLocalRandom.current().nextInt(1000) + 1;
```
这行代码生成了一个在 1 到 1000 之间的随机整数。使用 `ThreadLocalRandom` 确保了在多线程环境中生成随机数时的高效和安全。
总结:
`ThreadLocalRandom` 是在多线程环境中生成随机数的最佳选择,因为它提供了更高的性能和更低的资源争用。
===========
多线程就用Random怎么了 具体说
在多线程环境中使用 `java.util.Random` 而不是 `ThreadLocalRandom` 可能会导致以下几个问题:
### 1. **竞争条件和性能瓶颈**:
`Random` 类的实例在多线程环境中是共享的。如果多个线程同时访问同一个 `Random` 实例,会导致竞争条件和同步问题。为了防止这些问题,`Random` 的一些方法是同步的,这就会导致性能瓶颈。例如:
```java
public synchronized int nextInt(int bound) {
// Implementation
}
```
同步方法会导致线程在访问这些方法时被阻塞,从而降低并发性能。
### 2. **线程安全问题**:
如果在多线程环境中不使用同步机制而直接共享 `Random` 实例,可能会导致生成的随机数不正确或重复。这是因为 `Random` 类内部的状态在没有同步保护的情况下可能会被多个线程同时修改,导致不可预测的行为。
### 3. **资源争用**:
多个线程共享一个 `Random` 实例会导致资源争用,影响性能。这种争用会导致线程切换和上下文切换的开销,进一步降低系统的整体性能。
### 使用 `ThreadLocalRandom` 的好处:
1. **无锁设计**:
`ThreadLocalRandom` 是无锁的,每个线程都有自己的实例,不需要同步机制,因此避免了锁竞争和同步开销。
2. **高效性**:
因为每个线程都有自己的 `ThreadLocalRandom` 实例,生成随机数的操作是本地的,不会受到其他线程的影响,从而提高了性能。
3. **简洁性**:
使用 `ThreadLocalRandom` 可以避免显式地创建和管理 `Random` 实例,代码更加简洁。例如:
```java
int keyId = ThreadLocalRandom.current().nextInt(1000) + 1;
```
### 示例对比:
#### 使用 `Random` 的多线程示例:
```java
Random random = new Random();
Runnable task = () -> {
int keyId = random.nextInt(1000) + 1;
System.out.println(keyId);
};
for (int i = 0; i < 10; i++) {
new Thread(task).start();
}
```
在这个示例中,多个线程共享一个 `Random` 实例,可能会导致性能瓶颈和竞争条件。
#### 使用 `ThreadLocalRandom` 的多线程示例:
```java
Runnable task = () -> {
int keyId = ThreadLocalRandom.current().nextInt(1000) + 1;
System.out.println(keyId);
};
for (int i = 0; i < 10; i++) {
new Thread(task).start();
}
```
在这个示例中,每个线程都有自己的 `ThreadLocalRandom` 实例,没有竞争条件和同步开销,性能更高。
### 结论:
在多线程环境中使用 `ThreadLocalRandom` 而不是 `Random` 可以显著提高性能,避免竞争条件和同步问题。因此,在需要生成随机数的多线程应用中,推荐使用 `ThreadLocalRandom`。在多线程环境中使用 `java.util.Random` 而不是 `ThreadLocalRandom` 可能会导致以下几个问题:
### 1. **竞争条件和性能瓶颈**:
`Random` 类的实例在多线程环境中是共享的。如果多个线程同时访问同一个 `Random` 实例,会导致竞争条件和同步问题。为了防止这些问题,`Random` 的一些方法是同步的,这就会导致性能瓶颈。例如:
```java
public synchronized int nextInt(int bound) {
// Implementation
}
```
同步方法会导致线程在访问这些方法时被阻塞,从而降低并发性能。
### 2. **线程安全问题**:
如果在多线程环境中不使用同步机制而直接共享 `Random` 实例,可能会导致生成的随机数不正确或重复。这是因为 `Random` 类内部的状态在没有同步保护的情况下可能会被多个线程同时修改,导致不可预测的行为。
### 3. **资源争用**:
多个线程共享一个 `Random` 实例会导致资源争用,影响性能。这种争用会导致线程切换和上下文切换的开销,进一步降低系统的整体性能。
### 使用 `ThreadLocalRandom` 的好处:
1. **无锁设计**:
`ThreadLocalRandom` 是无锁的,每个线程都有自己的实例,不需要同步机制,因此避免了锁竞争和同步开销。
2. **高效性**:
因为每个线程都有自己的 `ThreadLocalRandom` 实例,生成随机数的操作是本地的,不会受到其他线程的影响,从而提高了性能。
3. **简洁性**:
使用 `ThreadLocalRandom` 可以避免显式地创建和管理 `Random` 实例,代码更加简洁。例如:
```java
int keyId = ThreadLocalRandom.current().nextInt(1000) + 1;
```
### 示例对比:
#### 使用 `Random` 的多线程示例:
```java
Random random = new Random();
Runnable task = () -> {
int keyId = random.nextInt(1000) + 1;
System.out.println(keyId);
};
for (int i = 0; i < 10; i++) {
new Thread(task).start();
}
```
在这个示例中,多个线程共享一个 `Random` 实例,可能会导致性能瓶颈和竞争条件。
#### 使用 `ThreadLocalRandom` 的多线程示例:
```java
Runnable task = () -> {
int keyId = ThreadLocalRandom.current().nextInt(1000) + 1;
System.out.println(keyId);
};
for (int i = 0; i < 10; i++) {
new Thread(task).start();
}
```
在这个示例中,每个线程都有自己的 `ThreadLocalRandom` 实例,没有竞争条件和同步开销,性能更高。
### 结论:
在多线程环境中使用 `ThreadLocalRandom` 而不是 `Random` 可以显著提高性能,避免竞争条件和同步问题。因此,在需要生成随机数的多线程应用中,推荐使用 `ThreadLocalRandom`。
===============
int keyId = ThreadLocalRandom.current().nextInt( bound: 1000)+1;string serialNo =uuID.randomuuID().tostring();
string key = ORDER KEY+keyId;String value ="京东订单"+serialNo;
redisTemplate.opsForValue().set(key,value);
log.info("***key:{}",key);log.info("***value:{}",value);
——————————————————
opsForValue干什么的
`opsForValue` 是 Spring Data Redis 中 `RedisTemplate` 提供的一个方法,用于操作 Redis 中的字符串类型数据。具体来说,`opsForValue` 返回一个 `ValueOperations` 对象,该对象提供了一系列方法来操作 Redis 中的字符串类型数据。
以下是 `opsForValue` 的一些常用方法:
1. **set(K key, V value)**:
- 设置指定键的值。如果键已经存在,则覆盖其旧值。
```java
redisTemplate.opsForValue().set("key", "value");
```
2. **get(Object key)**:
- 获取指定键的值。
```java
String value = redisTemplate.opsForValue().get("key");
```
3. **increment(K key, long delta)**:
- 将键的整数值增加指定的增量。
```java
redisTemplate.opsForValue().increment("key", 1);
```
4. **decrement(K key, long delta)**:
- 将键的整数值减少指定的减量。
```java
redisTemplate.opsForValue().decrement("key", 1);
```
5. **setIfAbsent(K key, V value)**:
- 如果键不存在,则设置键的值。
```java
redisTemplate.opsForValue().setIfAbsent("key", "value");
```
6. **setIfPresent(K key, V value)**:
- 如果键存在,则设置键的值。
```java
redisTemplate.opsForValue().setIfPresent("key", "value");
```
7. **getAndSet(K key, V value)**:
- 获取键的旧值并设置新值。
```java
String oldValue = redisTemplate.opsForValue().getAndSet("key", "newValue");
```
### 代码示例解析
```java
int keyId = ThreadLocalRandom.current().nextInt(1000) + 1;
String serialNo = UUID.randomUUID().toString();
String key = "ORDER_KEY" + keyId;
String value = "京东订单" + serialNo;
redisTemplate.opsForValue().set(key, value);
log.info("***key:{}", key);
log.info("***value:{}", value);
```
1. **生成随机数 `keyId`**:
```java
int keyId = ThreadLocalRandom.current().nextInt(1000) + 1;
```
生成一个 1 到 1000 之间的随机整数。
2. **生成 UUID `serialNo`**:
```java
String serialNo = UUID.randomUUID().toString();
```
生成一个唯一的 UUID 字符串。
3. **构建 Redis 键 `key`**:
```java
String key = "ORDER_KEY" + keyId;
```
构建一个键,格式为 "ORDER_KEY" 加上随机数。
4. **构建 Redis 值 `value`**:
```java
String value = "京东订单" + serialNo;
```
构建一个值,格式为 "京东订单" 加上 UUID。
5. **将键值对存储到 Redis**:
```java
redisTemplate.opsForValue().set(key, value);
```
使用 `opsForValue().set` 方法将键值对存储到 Redis 中。
6. **日志输出**:
```java
log.info("***key:{}", key);
log.info("***value:{}", value);
```
输出存储的键和值到日志中。
### 总结
`opsForValue` 是用于操作 Redis 中字符串类型数据的接口,提供了丰富的方法来进行各种操作。在上述代码中,使用 `opsForValue().set` 方法将生成的订单键值对存储到 Redis 中。
=================
加@Slf4j干嘛
`@Slf4j` 是 Lombok 提供的一个注解,用于自动生成日志记录器(Logger)对象。使用这个注解可以简化日志记录器的声明,避免手动创建日志记录器对象。
### 使用 `@Slf4j` 的好处
1. **简化代码**:
- 无需手动声明和初始化日志记录器对象,减少了样板代码。
- 例如,使用 `@Slf4j` 之前,通常需要如下代码来创建日志记录器:
```java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyClass {
private static final Logger log = LoggerFactory.getLogger(MyClass.class);
public void myMethod() {
log.info("This is a log message");
}
}
```
- 使用 `@Slf4j` 之后,只需在类上加上注解,Lombok 会自动生成日志记录器:
```java
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class MyClass {
public void myMethod() {
log.info("This is a log message");
}
}
```
2. **减少错误**:
- 手动创建日志记录器时,容易出错,比如拼写错误或使用错误的类名。使用 `@Slf4j` 可以避免这些错误。
3. **统一日志记录器**:
- Lombok 提供了多种日志注解(如 `@Log`, `@Log4j`, `@Log4j2`, `@Slf4j` 等),可以根据项目需求统一使用某种日志框架,提高代码一致性。
### 示例代码
结合你之前的代码示例,使用 `@Slf4j` 后的完整代码如下:
```java
import lombok.extern.slf4j.Slf4j;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class OrderService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
public void createOrder() {
int keyId = ThreadLocalRandom.current().nextInt(1000) + 1;
String serialNo = UUID.randomUUID().toString();
String key = "ORDER_KEY" + keyId;
String value = "京东订单" + serialNo;
redisTemplate.opsForValue().set(key, value);
log.info("***key:{}", key);
log.info("***value:{}", value);
}
}
```
### 解释
1. **`@Slf4j` 注解**:
- 自动生成一个名为 `log` 的 `Logger` 对象,无需手动创建。
2. **日志记录**:
- 使用 `log.info` 方法输出日志信息,记录生成的键和值。
3. **其他部分**:
- 使用 Spring 的 `RedisTemplate` 操作 Redis。
- 使用 `ThreadLocalRandom` 生成随机数。
- 使用 `UUID` 生成唯一标识符。
### 总结
`@Slf4j` 注解是 Lombok 提供的工具,用于自动生成日志记录器对象,简化代码,减少错误,提高代码一致性。在需要记录日志的类上使用 `@Slf4j` 注解,可以方便地进行日志记录。