作者简介,普修罗双战士,一直追求不断学习和成长,在技术的道路上持续探索和实践。
多年互联网行业从业经验,历任核心研发工程师,项目技术负责人。
欢迎 点赞✍评论⭐收藏
SpringBoot知识专栏学习
SpringBoot知识云集 | 访问地址 | 备注 |
---|---|---|
SpringBoot知识点(1) | https://blog.csdn.net/m0_50308467/article/details/135322153 | SpringBoot专栏 |
SpringBoot知识点(2) | https://blog.csdn.net/m0_50308467/article/details/135323253 | SpringBoot专栏 |
SpringBoot知识点(3) | https://blog.csdn.net/m0_50308467/article/details/135373512 | SpringBoot专栏 |
SpringBoot知识点(4) | https://blog.csdn.net/m0_50308467/article/details/135417447 | SpringBoot专栏 |
在 Spring Boot 中,常用的事务管理方式有如下几种:
1. 声明式事务管理
声明式事务管理是 Spring 的一种传统的事务管理方式,它的实现方式是通过对方法或类进行注解来实现,在需要进行事务管理时,通过 AOP 技术实现对事务进行拦截,在事务范围内执行方法。
在 Spring Boot 中,我们可以通过在方法上添加 @Transactional
注解来开启声明式事务管理,如下所示:
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Transactional
@Override
public void addUser(User user) {
userDao.save(user);
}
@Transactional
@Override
public void updateUser(User user) {
userDao.save(user);
}
@Transactional
@Override
public void deleteUser(Long userId) {
userDao.deleteById(userId);
}
}
2. 编程式事务管理
编程式事务管理是通过编写代码手动控制事务的提交和回滚。在 Spring Boot 中,我们可以通过 TransactionTemplate
或 PlatformTransactionManager
这两个接口来实现编程式事务管理。
下面是一个使用 TransactionTemplate
实现编程式事务管理的示例:
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Autowired
private TransactionTemplate transactionTemplate;
@Override
public void addUser(User user) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
userDao.save(user);
}
});
}
@Override
public void updateUser(User user) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
userDao.save(user);
}
});
}
@Override
public void deleteUser(Long userId) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
userDao.deleteById(userId);
}
});
}
}
3. JPA 自带的事务管理
对于使用 JPA 实现数据访问的应用程序,可以使用 JPA 自带的事务管理,它的实现方式是在 EntityManager
接口中提供了一个 Transaction
接口,通过该接口实现事务的提交和回滚。在 Spring Boot 中,我们可以使用 @Transactional
注解来开启 JPA 自带的事务管理,如下所示:
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Transactional
@Override
public void addUser(User user) {
userRepository.save(user);
}
@Transactional
@Override
public void updateUser(User user) {
userRepository.save(user);
}
@Transactional
@Override
public void deleteUser(Long userId) {
userRepository.deleteById(userId);
}
}
在使用以上三种方式时,均需注意事务的边界,保证数据的一致性和完整性,同时尽可能避免死锁和性能问题。
要在Spring Boot中实现分布式锁,可以使用Redis作为分布式锁的后端存储。下面详细说明实现分布式锁的每一步:
1. 添加Redis依赖:在项目的pom.xml中添加redis依赖,例如:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
2. 配置Redis连接信息:在Spring Boot的配置文件(如application.properties或application.yml)中配置Redis的连接信息,包括主机名、端口号、密码等。
3. 创建一个RedisTemplate实例:RedisTemplate是Spring提供的用于操作Redis的工具类。可以通过注解@Autowired将其注入到需要使用的类中。
@Autowired
private RedisTemplate<String, String> redisTemplate;
4. 实现分布式锁的获取方法:在需要获取分布式锁的地方,可以定义一个方法用于获取锁。方法内通过Redis的setIfAbsent
方法来设置一个key-value键值对,其中key作为锁的唯一标识,value可以是一个随机生成的唯一值,用于区分不同的线程。如果成功设置了锁,则表示当前线程获取到了锁。
public boolean tryLock(String lockName, String lockValue, long expireTime) {
Boolean result = redisTemplate.opsForValue().setIfAbsent(lockName, lockValue, expireTime, TimeUnit.MILLISECONDS);
return result != null && result;
}
5. 实现分布式锁的释放方法:在不需要锁的地方,需要释放分布式锁。可以定义一个方法用于释放锁。方法内通过Redis的del
方法删除指定的锁。
public void releaseLock(String lockName) {
redisTemplate.delete(lockName);
}
以上就是实现分布式锁的详细步骤。需要注意的是,获取锁时使用setIfAbsent
方法设置锁的时候应设置过期时间,以防止锁被某个线程长时间占用而无法释放,导致死锁的情况。
在Spring Boot中,事件驱动模型是通过Spring框架的事件机制来实现的。下面是实现事件驱动模型的基本步骤:
1. 创建自定义的事件类:创建一个继承自ApplicationEvent
的自定义事件类,该类表示特定的事件。
public class CustomEvent extends ApplicationEvent {
// 自定义事件的属性和方法
// ...
}
2. 创建事件发布者:在合适的地方创建一个事件发布者,负责发布事件。
@Component
public class EventPublisher {
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
public void publishEvent(Object source) {
CustomEvent customEvent = new CustomEvent(source);
applicationEventPublisher.publishEvent(customEvent);
}
}
3. 创建事件监听器:创建一个或多个事件监听器,用于处理特定的事件。监听器需要实现ApplicationListener
接口,并指定监听的事件类型。
@Component
public class EventListener implements ApplicationListener<CustomEvent> {
@Override
public void onApplicationEvent(CustomEvent event) {
// 处理事件的逻辑
}
}
4. 接收并处理事件:当事件发布者发布一个事件时,事件监听器会接收到该事件,并执行相应的处理逻辑。
通过上述步骤,Spring Boot实现了事件驱动模型。在应用程序中,当某个事件发生时,使用事件发布者发布该事件,然后事件监听器会监听并处理该事件。这种模型可以实现松耦合的组件之间的通信,使得各个组件可以更加独立和可测试。同时也支持多个监听器同时监听同一个事件,通过事件的机制,实现了解耦和异步处理的能力。
此外,Spring Boot还提供了一些其他的便捷功能,如使用注解@EventListener
在方法上直接标注监听事件,以及使用ApplicationEventMulticaster
自定义事件的发布和处理方式等。这样,开发者可以根据实际需求选择合适的方式来实现事件驱动模型。
Spring Boot中的优雅停机是指在应用关闭时,能够让应用先处理完已有的请求任务,然后再关闭,确保应用退出过程中不会造成任何数据的丢失。下面介绍一下Spring Boot中实现优雅停机的几种方式:
1. 使用Spring Boot的自带功能spring.lifecycle.timeout-per-shutdown-phase
,这个属性会在应用退出时给予每个上下文一定时间来执行清理任务。例如,可以在application.properties
配置文件中设置:
spring.lifecycle.timeout-per-shutdown-phase=60s
这样,在关闭应用时,Spring Boot会先停止接受请求,等待60秒,然后关闭应用。
2. 自定义中央管理类GracefulShutdownHandler
,继承ApplicationListener
并实现ContextClosedEvent
接口,通过监听ContextClosedEvent
来捕获应用关闭事件,然后通过Thread.sleep()
等方式等待当前处理的任务完成。
@Component
public class GracefulShutdownHandler implements ApplicationListener<ContextClosedEvent> {
private static final Logger log = LoggerFactory.getLogger(GracefulShutdownHandler.class);
@Autowired
private WebServerGracefulShutdownHandler webServerGracefulShutdownHandler;
@Autowired
private Executor executor;
@Value("${graceful.shutdown.timeout:30}")
private int timeoutInSeconds;
@Override
public void onApplicationEvent(ContextClosedEvent event) {
log.info("Graceful shutdown initiated, waiting for active requests to complete");
// gracefully shut down the embedded web server
webServerGracefulShutdownHandler.shutdown();
// wait for tasks to complete
try {
concurrentExecutorShutdown(timeoutInSeconds);
} catch (InterruptedException e) {
log.info("Interrupted while waiting for tasks to complete", e);
Thread.currentThread().interrupt();
}
}
private void concurrentExecutorShutdown(int timeout) throws InterruptedException {
executor.shutdown();
if(!executor.awaitTermination(timeout, TimeUnit.SECONDS)) {
log.warn("The executor still has a long running task after {} seconds", timeout);
}
}
}
3. 使用Spring Boot Actuator的shutdown端点,可以通过访问http://localhost:port/actuator/shutdown 发送一个POST请求,让应用停止接受新的请求并优雅的关闭,但是要注意需要在application.properties
中设置management.endpoint.shutdown.enabled=true
开启该功能。
@Configuration
public class CustomActuatorEndpointConfig {
@Bean
public ShutdownEndpoint shutdownEndpoint() {
return new ShutdownEndpoint();
}
@Bean
public GracefulShutdownEndpoint gracefulShutdownEndpoint(GracefulShutdownHandler gracefulShutdownHandler) {
return new GracefulShutdownEndpoint(gracefulShutdownHandler);
}
}
通过上述方式,可以简单地实现Spring Boot中的优雅停机,让应用能够更加安全、稳定、不丢数据地停止。
在Spring Boot中实现单点登录(SSO)可以通过整合Spring Security和Spring Security OAuth2来实现。下面是一种基本的实现方式:
1. 添加依赖:在pom.xml
文件中添加Spring Security和Spring Security OAuth2的依赖。
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-securityartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-oauth2-clientartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-oauth2-resource-serverartifactId>
dependency>
dependencies>
2. 配置Spring Security:在application.properties
文件中配置Spring Security的相关属性。
# 开启Spring Security
spring.security.oauth2.client.registration..client-id=
spring.security.oauth2.client.registration..client-secret=
spring.security.oauth2.client.registration..redirect-uri=
spring.security.oauth2.client.registration..client-name=
spring.security.oauth2.client.registration..provider=
其中,
是你的客户端ID,
是你的客户端密钥,
是登录后重定向的URI,
是可选的客户端名称,
是提供SSO服务的提供方。
3. 创建登录页面:创建一个登录页面,用于用户进行登录。可以使用Thymeleaf或其他模板引擎来创建页面。
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Logintitle>
head>
<body>
<h2>Loginh2>
<form th:action="@{/login}" method="post">
<input type="text" name="username" placeholder="Username" />
<input type="password" name="password" placeholder="Password" />
<input type="submit" value="Login" />
form>
body>
html>
4. 创建资源服务器:创建一个资源服务器,用于验证用户的登录状态和处理受保护的资源。
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/login").permitAll()
.antMatchers("/protected-resource").authenticated();
}
}
5. 创建回调接口:创建一个回调接口,用于处理成功登录后的回调。
@Controller
public class LoginCallbackController {
@RequestMapping("/login/callback")
public String loginCallback() {
// 处理登录成功后的逻辑
return "redirect:/protected-resource";
}
}
以上是一个基本的单点登录(SSO)的实现方式,具体的实现可能会根据具体的需求和业务场景有所变化。此外,还可以根据需要自定义登录页面、认证逻辑和权限控制等。
Spring Boot 中的国际化和本地化支持可以通过以下步骤实现:
1. 在 src/main/resources
目录下新建 messages.properties
文件,该文件就是默认的国际化资源文件,里面放置着系统的默认文案。
2. 在 messages.properties
中添加各个需要国际化支持的文本,并为其分配唯一的 key 值,比如:
welcome.msg=欢迎来到 Spring Boot
3. 新建其他语言的本地化资源文件,如 messages_en_US.properties
,其中 en_US
代表英语区域,其它的语言区域,参照相关标准修改即可。
4. 在 messages_en_US.properties
中添加与原来的 messages.properties
中对应的国际化文本,比如:
welcome.msg=Welcome to Spring Boot
5. 在需要进行国际化的地方,使用 MessageSource
进行文本的获取,例如:
@Autowired
private MessageSource messageSource;
public String getHello() {
return messageSource.getMessage("welcome.msg", null, LocaleContextHolder.getLocale());
}
其中,MessageSource
是 Spring 提供的用于获取文本的接口,getMessage()
方法可以根据 key 值获取对应的文本,第二个参数用于传递参数,第三个参数 LocaleContextHolder.getLocale()
方法用于获取当前的语言区域。这样,就可以根据不同的语言区域返回不同的文本内容了。
此外,在 Spring Boot 中,还可以在配置文件中配置国际化文件的基础名称,例如:
spring.messages.basename=messages
这样 Spring Boot 就会自动去寻找 messages.properties
、messages_en_US.properties
等本地化资源文件,并将其加载到应用中。
总之,Spring Boot 中的国际化和本地化支持非常简单易用,只需要遵循一定的命名规范,并使用 MessageSource
进行文本的获取即可。
在 Spring Boot 中集成第三方框架或工具通常需要以下几个步骤:
1. 导入依赖:在你的项目的 pom.xml
文件中添加相应的依赖。你可以通过 Maven Central 或其他仓库来查找需要的库的依赖坐标。例如:
<dependencies>
<dependency>
<groupId>com.examplegroupId>
<artifactId>example-libraryartifactId>
<version>1.0.0version>
dependency>
dependencies>
2. 配置和使用:根据第三方框架或工具的要求,进行相应的配置和使用。例如,如果你要集成一个数据库框架,你需要在 application.properties
或 application.yml
中配置数据库连接信息,然后在你的代码中使用相应的类和方法来操作数据库。
3. 自动配置:Spring Boot 提供了许多自动配置的功能,可以简化第三方框架或工具的集成。如果第三方库符合一些特定的命名约定,Spring Boot 可能会自动为你进行必要的配置。你可以查看 Spring Boot 的官方文档来了解更多关于自动配置的信息。
4. 自定义配置:如果第三方框架或工具的集成需要一些特定的配置信息,你可以在 application.properties
或 application.yml
中添加相应的配置项,并通过 @Value
注解或 @ConfigurationProperties
注解将其注入到你的代码中。
5. 对接其他组件:有时,你可能还需要对接其他的组件来实现更复杂的功能。你可以使用 Spring Boot 提供的注解、接口或扩展点来与这些组件进行集成。例如,你可以使用 Spring MVC 的 @RestController
注解来定义 RESTful API,或者使用 Spring Security 来添加认证和授权的功能。
这些是集成第三方框架或工具的基本步骤,具体的集成方式和步骤会根据具体的框架或工具而有所不同。建议查阅相关框架或工具的官方文档或示例代码来获取更详细的集成指导。
在 Spring Boot 中,你可以使用 Spring Cloud 提供的 Eureka 来实现服务注册与发现。以下是实现步骤:
1. 引入相应的依赖:在你的项目的 pom.xml
文件中添加 Eureka 相关的依赖。例如:
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
dependency>
dependencies>
2. 配置服务注册中心:在 application.properties
或 application.yml
中配置 Eureka 服务注册中心的相关信息。例如:
spring:
application:
name: service-registry
server:
port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false
这里的 spring.application.name
指定了服务注册中心应用的名称,server.port
指定了服务注册中心的端口号,eureka.client.register-with-eureka
和 eureka.client.fetch-registry
配置为 false 表示该应用不需要自己注册到其他的服务注册中心,也不需要获取注册中心的服务信息。
3. 启用服务注册中心:在启动类上添加 @EnableEurekaServer
注解来启用服务注册中心。例如:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class ServiceRegistryApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceRegistryApplication.class, args);
}
}
4. 配置服务提供者和消费者:对于服务提供者和消费者,你需要添加 spring-cloud-starter-netflix-eureka-client
依赖并配置相应的信息。例如:
spring:
application:
name: service-provider
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
spring.application.name
指定了当前服务的名称,eureka.client.service-url.defaultZone
指定了注册中心的地址。
5. 启用服务提供者和消费者:在启动类上添加 @EnableDiscoveryClient
注解来启用服务提供者和消费者。例如:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class ServiceProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceProviderApplication.class, args);
}
}
6. 注册服务、发现服务:在服务提供者中,你可以使用 @RestController
和 @RequestMapping
注解定义 RESTful API,并使用 @EnableDiscoveryClient
注解来将服务注册到 Eureka 服务注册中心。
在服务消费者中,你可以使用 RestTemplate
或者 Feign 等客户端工具来调用其他服务。Spring Cloud 会根据服务注册中心的信息来进行服务发现和负载均衡。
通过以上步骤,你就可以在 Spring Boot 中实现服务注册与发现了。当你的服务提供者启动后,它会向 Eureka 注册中心注册自己的信息。而当服务消费者启动后,它会从 Eureka 注册中心上获取所有可用的服务列表,并通过负载均衡策略调用这些服务。
在 Spring Boot 中,你可以使用 Spring Boot Starter JDBC 或 Spring Boot Starter Data JPA 来简化连接池的配置,另外,你可以使用 application.properties
或 application.yml
来自定义连接池的相关属性。
以下是几种常见的连接池:
1. HikariCP 连接池
HikariCP 是目前性能最好的连接池,它的配置也很简单。在 Spring Boot 中,你只需在 application.properties
或 application.yml
中定义以下属性:
spring.datasource.hikari.jdbc-url=jdbc:mysql://localhost:3306/test
spring.datasource.hikari.username=root
spring.datasource.hikari.password=root
spring.datasource.hikari.driver-class-name=com.mysql.jdbc.Driver
这样,就启用了 HikariCP 连接池,并通过属性指定了数据库的连接参数。
2. Tomcat JDBC 连接池
Tomcat JDBC 连接池是 Apache Tomcat 项目的一部分,它的配置相对于 HikariCP 来说稍微繁琐一些。你需要在 pom.xml
中添加以下依赖:
<dependency>
<groupId>org.apache.tomcatgroupId>
<artifactId>tomcat-jdbcartifactId>
<version>${tomcat.version}version>
dependency>
其中 ${tomcat.version}
指定 Tomcat 版本号。然后,在 application.properties
或 application.yml
中添加以下配置信息:
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.tomcat.initial-size=5
spring.datasource.tomcat.max-active=20
spring.datasource.tomcat.max-idle=5
spring.datasource.tomcat.min-idle=2
spring.datasource.tomcat.max-wait=10000
这里的 spring.datasource.tomcat
配置项指定了Tomcat JDBC 连接池的相关属性。
3. Druid 连接池
Druid 是一个开源的数据库连接池和 SQL 监控工具,它的配置也比较简单。在 Spring Boot 中,你只需在 application.properties
或 application.yml
中定义以下属性:
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.initial-size=5
spring.datasource.min-idle=5
spring.datasource.max-active=20
spring.datasource.max-wait=60000
spring.datasource.time-between-eviction-runs-millis=60000
spring.datasource.min-evictable-idle-time-millis=300000
spring.datasource.validation-query=SELECT 1 FROM DUAL
spring.datasource.test-while-idle=true
spring.datasource.test-on-borrow=false
spring.datasource.test-on-return=false
spring.datasource.pool-prepared-statements=true
spring.datasource.max-pool-prepared-statement-per-connection-size=20
spring.datasource.filters=stat,wall,log4j
spring.datasource.connection-properties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
这里的 spring.datasource
配置项指定了 Druid 连接池的相关属性。
关于线程池的使用,你可以使用 Spring 框架自带的 ThreadPoolTaskExecutor 来实现线程池的配置。你可以在配置文件中添加以下属性:
spring.task.execution.pool.max-threads=5
spring.task.execution.pool.queue-capacity=100
这里的 spring.task.execution.pool
配置项指定了线程池的最大线程数和任务队列容量。同时,在代码中,你可以使用 @Async
和 @EnableAsync
注解来使用这个线程池。
下面是一个使用Java实现线程池的简单示例代码:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExample {
public static void main(String[] args) {
// 创建线程池,设置最大线程数为3
ExecutorService executor = Executors.newFixedThreadPool(3);
// 提交任务给线程池
executor.submit(new Task("Task 1"));
executor.submit(new Task("Task 2"));
executor.submit(new Task("Task 3"));
// 关闭线程池
executor.shutdown();
}
// 定义要执行的任务
static class Task implements Runnable {
private final String message;
public Task(String message) {
this.message = message;
}
@Override
public void run() {
System.out.println("Executing task: " + message);
}
}
}
上述代码使用了Java的java.util.concurrent
包提供的ExecutorService
接口和Executors
工具类来创建和管理线程池。
通过Executors.newFixedThreadPool(3)
创建一个固定线程数为3的线程池。
然后使用executor.submit(new Task("Task x"))
方法来向线程池提交任务,这里提交了三个任务。
最后,调用executor.shutdown()
方法关闭线程池。注意,关闭线程池后将不再接受新的任务提交,但会等待已提交的任务完成执行。
Spring Boot中可以采用如下几种方式来优化应用性能:
1. 使用缓存:缓存是提高应用性能的重要手段,可以使用Spring Cache来实现缓存的配置和管理。
2. 使用异步调用:异步处理对于一些IO密集型操作,可以有效提高应用的吞吐量和性能。Spring提供了@Async
注解来支持异步方法调用。
3. 使用线程池:线程池可以避免频繁的线程创建和销毁,提高线程的复用率,从而提高应用的性能。可以使用ThreadPoolTaskExecutor
类来创建线程池。
4. 数据库连接池的优化:可以使用HikariCP、Druid等连接池来优化数据库连接处理的性能。
5. 调整应用配置:例如调整最小、最大线程数、线程池队列容量等参数,调整JVM内存配置等,都可以影响应用的性能表现。
6. 使用缓存数据查询:使用缓存数据查询可以避免频繁的数据库查询操作,从而减少响应时间,并避免数据库负载过大。
7. 使用性能优化工具:比如JProfiler、VisualVM等工具可以用于查看应用中的性能瓶颈和问题,并提供相应的解决方案。
需要注意的是,具体应该采取哪些方式来优化应用性能,需要根据实际情况进行权衡和选择,以取得最好的性能表现。