Springboot+Druid 动态数据源配置监控
一、引入maven依赖,使用 starter 与原生 druid 依赖配置有所不同
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.8</version> </dependency>
二、配置数据源
spring:
datasource:
druid:
filter:
stat: #开启sql监控
enabled: true
wall:
enabled: true
slf4j:
enabled: true
DB1:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:sqlserver://127.0.0.1:1487;DatabaseName=CN2018
username: root
password: 12345
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
# 连接池的配置信息
initial-size: 5
min-idle: 5
maxActive: 20
maxWait: 60000 # 配置获取连接等待超时的时间
timeBetweenEvictionRunsMillis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
minEvictableIdleTimeMillis: 300000 # 配置一个连接在池中最小生存的时间,单位是毫秒
# validationQuery: SELECT 1 FROM DUAL # mysql数据库
validationQuery: SELECT 1 # sqlserver 数据库
poolPreparedStatements: true # 打开PSCache,并且指定每个连接上PSCache的大小
maxPoolPreparedStatementPerConnectionSize: 20
DB2:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:sqlserver://127.0.0.1:1488;DatabaseName=DB2022
username: root
password: 123456
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
# 连接池的配置信息
initial-size: 1
min-idle: 1
maxActive: 5
maxWait: 60000 # 配置获取连接等待超时的时间
timeBetweenEvictionRunsMillis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
minEvictableIdleTimeMillis: 300000 # 配置一个连接在池中最小生存的时间,单位是毫秒
# validationQuery: SELECT 1 FROM DUAL # mysql数据库
validationQuery: SELECT 1 # sqlServer 数据库
poolPreparedStatements: true # 打开PSCache,并且指定每个连接上PSCache的大小
maxPoolPreparedStatementPerConnectionSize: 20
三、创建配置类
//记录数据库名 public interface ContextConst { enum DataSourceType{ DB1,DB2 } }
//数据源持有类 @Slf4j public class DataSourceContextHolder { /** * CONTEXT_HOLDER代表一个可以存放String类型的ThreadLocal对象, * 此时任何一个线程可以并发访问这个变量, * 对它进行写入、读取操作,都是线程安全的。 * 比如一个线程通过CONTEXT_HOLDER.set(“aaaa”);将数据写入ThreadLocal中, * 在任何一个地方,都可以通过CONTEXT_HOLDER.get();将值获取出来。 * 这里写入的就是数据库名, */ private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>(); public static void setDataSource(String dbType){ CONTEXT_HOLDER.set(dbType); } public static String getDataSource(){ return CONTEXT_HOLDER.get(); } public static void clearDataSource(){ CONTEXT_HOLDER.remove(); } }
//数据源路由实现类 public class DynamicDataSource extends AbstractRoutingDataSource { /** * @Description:数据源路由实现类 AbstractRoutingDataSource(每执行一次数据库 , 动态获取DataSource) */ @Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.getDataSource(); } }
//自定义切换数据源注解 @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface TargetDateSouce { ContextConst.DataSourceType value() default ContextConst.DataSourceType.DB1; }
//AOP动态数据源通知 @Component @Aspect @Order(-1) //保证在@Transactional之前执行,必须加上,不然无法分辨是哪个数据源在执行事务 @Slf4j public class DynamicDataSourceAspect { @Before("execution(* com.blaze.pboc.service..*.*(..))") public void before(JoinPoint point) { try { TargetDateSouce annotationOfClass = point.getTarget().getClass().getAnnotation(TargetDateSouce.class); String methodName = point.getSignature().getName(); Class[] parameterTypes = ((MethodSignature) point.getSignature()).getParameterTypes(); Method method = point.getTarget().getClass().getMethod(methodName, parameterTypes); TargetDateSouce methodAnnotation = method.getAnnotation(TargetDateSouce.class); methodAnnotation = methodAnnotation == null ? annotationOfClass : methodAnnotation; ContextConst.DataSourceType dataSourceType = methodAnnotation != null && methodAnnotation.value() != null ? methodAnnotation.value() : ContextConst.DataSourceType.DB1; DataSourceContextHolder.setDataSource(dataSourceType.name()); } catch (NoSuchMethodException e) { log.error("error", e); } } @After("execution(* com.blaze.pboc.service..*.*(..))") public void after(JoinPoint point) { DataSourceContextHolder.clearDataSource(); } }
//动态数据源配置类 @SpringBootConfiguration public class DruidDataSourceConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource.druid.db1") public DruidDataSource masterDataSource() { return DruidDataSourceBuilder.create().build(); } @Bean @ConfigurationProperties(prefix = "spring.datasource.druid.db2") public DruidDataSource clusterDataSource() { DruidDataSource druidDataSource = DruidDataSourceBuilder.create().build(); return druidDataSource; } @Primary @Bean public DataSource dynamicDataSource() { DynamicDataSource dynamicDataSource = new DynamicDataSource(); //配置默认数据源 dynamicDataSource.setDefaultTargetDataSource(masterDataSource()); //配置多数据源这里的key一定要是string类型,枚举类型并不支持,所以用到枚举中name()方法转成string,或者用toString方法。 HashMap<Object, Object> dataSourceMap = new HashMap(); dataSourceMap.put(ContextConst.DataSourceType.DB1.name(), masterDataSource()); dataSourceMap.put(ContextConst.DataSourceType.DB2.name(), clusterDataSource()); dynamicDataSource.setTargetDataSources(dataSourceMap); return dynamicDataSource; } // 配置@Transactional注解事务 @Bean public PlatformTransactionManager transactionManager() { return new DataSourceTransactionManager(dynamicDataSource()); } //配置 Druid 监控管理后台的Servlet; //内置 Servlet 容器时没有web.xml文件,所以使用 Spring Boot 的注册 Servlet 方式 @Bean public ServletRegistrationBean registrationBean() { ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*"); Map<String, String> initParameters = new HashMap<>(); initParameters.put("loginUsername", "admin"); initParameters.put("loginPassword", "12345"); bean.setInitParameters(initParameters); return bean; } //去除Druid监控页面的广告 @Bean public FilterRegistrationBean removeDruidAdFilter() throws IOException { String text = Utils.readFromResource("support/http/resources/js/common.js"); final String newJs = text.replace("this.buildFooter();", ""); // 新建一个过滤器注册器对象 FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>(); // 注册common.js文件的过滤器 registration.addUrlPatterns("/druid/js/common.js"); // 添加一个匿名的过滤器对象,并把改造过的common.js文件内容写入到浏览器 registration.setFilter((servletRequest, servletResponse, filterChain) -> { // 重置缓冲区,响应头不会被重置 servletResponse.resetBuffer(); // 把改造过的common.js文件内容写入到浏览器 servletResponse.getWriter().write(newJs); }); return registration; } }
四、测试,常用的数据源配置db1,无需添加注解
五、登陆 web 监控端
http://127.0.0.1:9000/api/druid/login.html