Springboot+Druid 動態資料來源配置監控
阿新 • • 發佈:2022-01-14
一、引入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 voidclearDataSource(){ 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