风离不摆烂学习日志 Day11 SpringBoot集成Mysql 配置开关以及优雅关闭

问题引入

1、现在的数据库配置,不能通过开关配置加载,需要改造成如Redis那种可控的开关
2、现在部署都是直接杀掉,并没有考虑正在运行的是否完成

配置Mysql 开关配置加载

取消自动配置的数据源

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})

启用手动来配置数据源

查找资料:

https://blog.csdn.net/sqlgao22/article/details/96476754

 @ConditionalOnProperty(prefix = "spring.datasource.druid.XXX", name = "switch", havingValue = "open") //为open则启用

配合 注解是否启用数据源 达到 配置开关数据的效果

package ****; //手动打码


import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.XXX.tailor.channel.config.middle.datasource.DynamicDataSource;
import com.XXX.tailor.channel.config.middle.properties.DruidProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;


import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;


@Configuration
@Slf4j
public class DruidConfig {

    @Value("${spring.datasource.druid.XXX.url}")
    private String XXX;

    @Value("${spring.datasource.druid.XXX.password}")
    private String xxxPassword;

    @Value("${spring.datasource.druid.xxx.username}")
    private String XXXUsername;

 @Bean
    @ConfigurationProperties("spring.datasource.druid.xxx")
    @ConditionalOnProperty(prefix = "spring.datasource.druid.xxx", name = "switch", havingValue = "open") //为open则启用
 public DataSource masterDataSource(DruidProperties druidProperties) {
        log.info("当前启用的数据库为: xxx");
        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
     return druidProperties.dataSource(dataSource);
    }
   
}
   

image-20221130013111695

优雅停止 SpringBoot项目

监听Pid

package top.flya;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.ApplicationPidFileWriter;

@SpringBootApplication
@MapperScan("top.flya.mapper")
public class Application {

	public static void main(String[] args) {
		SpringApplication application = new SpringApplication(Application.class);
		application.addListeners(new ApplicationPidFileWriter("/home/luyi/Desktop/app.pid"));
		application.run();
//
//		SpringApplication.run(Application.class, args);
		System.out.println("启动成功:http://127.0.0.1:8080");
	}
	
}

在springboot启动的时候将进程号写入一个app.pid文件,生成的路径是可以指定的,可以通过命令直接停止服务(进程ID可以直接在这个文件中看到),这个时候bean对象的PreDestroy方法也会调用的。这种方法大家使用的比较普遍,写一个start.sh用于启动springboot程序,然后写一个停止程序将服务停止。

SpringApplication.exit()

        
public static void exitApplication(ConfigurableApplicationContext context) {
    int exitCode = SpringApplication.exit(context, (ExitCodeGenerator) () -> 0);
    System.exit(exitCode);
}

通过调用一个SpringApplication.exit()方法也可以退出程序,同时将生成一个退出码,这个退出码可以传递给所有的context。这个就是一个JVM的钩子,通过调用这个方法的话会把所有PreDestroy的方法执行并停止,并且传递给具体的退出码给所有Context。通过调用System.exit(exitCode)可以将这个错误码也传给JVM。程序执行完后最后会输出:Process finished with exit code 0,给JVM一个SIGNAL

对外暴露一个接口 调用这个退出函数即可

image-20221130003942139

利用spring-boot-starter-actuator

添加依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

开启配置

management:
  server:
    ## 访问端口
    port: 8081
  endpoint:
    shutdown:
      enabled: true
  endpoints:
    web:
      #base-path: 默认为/actuator
      exposure:
        include:
          - shutdown

发送关闭请求

//一定要POST 访问
curl -X pcurl -X POST http://localhost:8081/actuator/shutdown

image-20221130010224400