SpringBoot(13)---整合Druid實現多數據源和可視化監控


SpringBoot整合Druid實現多數據源和可視化監控

先獻上github代碼地址:https://github.com/yudiandemingzi/spring-boot-many-data-source
代碼拉下來換下自己的mysql數據庫地址,就可以直接運行。Druid的優點很明顯,它的可視化界面可以監控Sql語句和URI執行情況在開發中真的很需要。
先說優點吧:

    1) 替換DBCP和C3P0。Druid提供了一個高效、功能強大、可擴展性好的數據庫連接池。
    2) 數據庫密碼加密。直接把數據庫密碼寫在配置文件中,這是不好的行為,容易導致安全問題。
    3) 可以監控數據庫訪問性能,能夠詳細統計SQL的執行性能,這對於線上分析數據庫訪問性能有幫助。
    4) SQL執行日志,Druid提供了不同的LogFilter,監控你應用的數據庫   訪問情況。
    5)擴展JDBC,如果你要對JDBC層有編程的需求,可以通過Druid提供的Filter-Chain機制,很方便編寫JDBC層的擴展插件。

二、配置多數據源

1、pom.xml

只需要添加druid這一個jar就行了,有關springboot項目他還有個整合包,用那個整合包也一樣。

       <!-- Druid 數據連接池依賴 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.8</version>
        </dependency>
        <dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid-spring-boot-starter</artifactId>
			<version>1.1.6</version>
		</dependency>

對於springboot項目來講,上面任選一個都是可以的,親測有效。

2、application.yml

我這里是采用application.yml進行添加配置,這里面配置了兩個數據源,其實在application.yml也可以不配置這些東西,它的主要作用是給數據源配置類讀取數據用的。

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    initialSize: 10
    minIdle: 10
    maxActive: 200
    # 配置獲取連接等待超時的時間
    maxWait: 60000
    # 配置間隔多久才進行一次檢測,檢測需要關閉的空閑連接,單位是毫秒
    timeBetweenEvictionRunsMillis: 60000
    # 配置一個連接在池中最小生存的時間,單位是毫秒
    minEvictableIdleTimeMillis: 30000
    validationQuery: select 'x'
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    # 打開PSCache,並且指定每個連接上PSCache的大小
    poolPreparedStatements: true
    maxPoolPreparedStatementPerConnectionSize: 20
    # 配置監控統計攔截的filters
    filters: stat,wall,slf4j
    # 通過connectProperties屬性來打開mergeSql功能;慢SQL記錄
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000


#配置了兩個數據源
master:
  datasource:
    url: jdbc:mysql://localhost:3306/user?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true
    username: root
    password: root
    driverClassName: com.mysql.jdbc.Driver

cluster:
  datasource:
    url: jdbc:mysql://localhost:3306/student?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true
    username: root
    password: root
    driverClassName: com.mysql.jdbc.Driver

3、主數據源配置類(MasterDataSourceConfig)

/**
 * 主數據源配置
 */
@Configuration
@MapperScan(basePackages = MasterDataSourceConfig.PACKAGE, sqlSessionFactoryRef = "masterSqlSessionFactory")
public class MasterDataSourceConfig {

    /**
     * 配置多數據源 關鍵就在這里 這里配置了不同的數據源掃描不同mapper
     */
    static final String PACKAGE = "com.binron.multidatasource.mapper.master";
    static final String MAPPER_LOCATION = "classpath:mapper/master/*.xml";

    /**
     * 連接數據庫信息 這個其實更好的是用配置中心完成
     */
    @Value("${master.datasource.url}")
    private String url;  
      
    @Value("${master.datasource.username}")
    private String username;  
      
    @Value("${master.datasource.password}")
    private String password;  
      
    @Value("${master.datasource.driverClassName}")
    private String driverClassName;


    /**
     * 下面的配置信息可以讀取配置文件,其實可以直接寫死 如果是多數據源的話 還是考慮讀取配置文件
     */
    @Value("${spring.datasource.initialSize}")
    private int initialSize;  
      
    @Value("${spring.datasource.minIdle}")
    private int minIdle;  
      
    @Value("${spring.datasource.maxActive}")
    private int maxActive;  
      
    @Value("${spring.datasource.maxWait}")
    private int maxWait;  
      
    @Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
    private int timeBetweenEvictionRunsMillis;  
      
    @Value("${spring.datasource.minEvictableIdleTimeMillis}")
    private int minEvictableIdleTimeMillis;  
      
    @Value("${spring.datasource.validationQuery}")
    private String validationQuery;  
      
    @Value("${spring.datasource.testWhileIdle}")
    private boolean testWhileIdle;  
      
    @Value("${spring.datasource.testOnBorrow}")
    private boolean testOnBorrow;  
      
    @Value("${spring.datasource.testOnReturn}")
    private boolean testOnReturn;  
      
    @Value("${spring.datasource.poolPreparedStatements}")
    private boolean poolPreparedStatements;  
      
    @Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize}")
    private int maxPoolPreparedStatementPerConnectionSize;  
      
    @Value("${spring.datasource.filters}")
    private String filters;
      
    @Value("{spring.datasource.connectionProperties}")
    private String connectionProperties;  
    
    
    @Bean(name = "masterDataSource")
    @Primary //標志這個 Bean 如果在多個同類 Bean 候選時,該 Bean 優先被考慮。
    public DataSource masterDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(url);  
        dataSource.setUsername(username);  
        dataSource.setPassword(password);  
        dataSource.setDriverClassName(driverClassName);  
          
        //具體配置 
        dataSource.setInitialSize(initialSize);  
        dataSource.setMinIdle(minIdle);  
        dataSource.setMaxActive(maxActive);  
        dataSource.setMaxWait(maxWait);  
        dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);  
        dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);  
        dataSource.setValidationQuery(validationQuery);  
        dataSource.setTestWhileIdle(testWhileIdle);  
        dataSource.setTestOnBorrow(testOnBorrow);  
        dataSource.setTestOnReturn(testOnReturn);  
        dataSource.setPoolPreparedStatements(poolPreparedStatements);  
        dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);

        /**
         * 這個是用來配置 druid 監控sql語句的 非常有用 如果你有兩個數據源 這個配置哪個數據源就監控哪個數據源的sql 同時配置那就都監控
         */
        try {
            dataSource.setFilters(filters);
        } catch (SQLException e) {
        	e.printStackTrace();
        }
        dataSource.setConnectionProperties(connectionProperties);  
        return dataSource;
    }

    @Bean(name = "masterTransactionManager")
    @Primary
    public DataSourceTransactionManager masterTransactionManager() {
        return new DataSourceTransactionManager(masterDataSource());
    }

    @Bean(name = "masterSqlSessionFactory")
    @Primary
    public SqlSessionFactory masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource masterDataSource)
            throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(masterDataSource);
        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MasterDataSourceConfig.MAPPER_LOCATION));
        
        return sessionFactory.getObject();
    }
}

這里說明幾點

  1) @Primary: 多數據源配置的時候注意,必須要有一個主數據源, 用 @Primary 標志該 Bean。標志這個 Bean 如果在多個同類 Bean 候選時,該 Bean優先被考慮。
  2) dataSource.setFilters(filters): 這個是用來配置 druid 監控sql語句的, 如果你有兩個數據源 這個配置哪個數據源就監控哪個 數據源的sql,同時配置那就都監控。
  3) 能夠做到多個數據源的關鍵點 就是每個數據源所掃描的mapper包不一樣,誰掃描到哪個mapper那么該mapper就用哪個數據源,同時都掃到了呢,
      那當然就得用主數據源咯,也就是添加@Primary 的數據源。

4、次數據源(ClusterDataSourceConfig)

這里省略了部分代碼,因為和主是一樣的,完整代碼在github代碼里有。

/**
 * 次數據源 另一個數據源配置
 */
@Configuration
@MapperScan(basePackages = ClusterDataSourceConfig.PACKAGE, sqlSessionFactoryRef = "clusterSqlSessionFactory")
public class ClusterDataSourceConfig {

    /**
     * 配置多數據源 關鍵就在這里 這里配置了不同數據源掃描不同的mapper
     */
    static final String PACKAGE = "com.binron.multidatasource.mapper.cluster";
    static final String MAPPER_LOCATION = "classpath:mapper/cluster/*.xml";

    @Value("${cluster.datasource.url}")
    private String url;

    @Value("${cluster.datasource.username}")
    private String username;

    @Value("${cluster.datasource.password}")
    private String password;

    @Value("${cluster.datasource.driverClassName}")
    private String driverClass;

    @Bean(name = "clusterDataSource")
    public DataSource clusterDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setDriverClassName(driverClass);

        //具體配置
        try {
            dataSource.setFilters("stat,wall,slf4j");
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return dataSource;
    }

    @Bean(name = "clusterTransactionManager")
    public DataSourceTransactionManager clusterTransactionManager() {
        return new DataSourceTransactionManager(clusterDataSource());
    }

    @Bean(name = "clusterSqlSessionFactory")
    public SqlSessionFactory clusterSqlSessionFactory(@Qualifier("clusterDataSource") DataSource clusterDataSource)
            throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(clusterDataSource);

        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(ClusterDataSourceConfig.MAPPER_LOCATION));
        return sessionFactory.getObject();
    }
}

這里說明幾點:

   1)發現次數據源所掃描的mapper和主是完全不一樣的,說明每個數據源負責自己的mapper
   2)  次數據源是沒有加@Primary。
   3)這里也添加了dataSource.setFilters(filters):說明 次數據源也需要監聽sql語句。

三、配置可視化界面

直接上代碼:

/**
 * druid監控界面設置
 */
@Configuration
public class DruidConfiguration {

    @Bean
    public ServletRegistrationBean druidStatViewServle() {
        //注冊服務
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(
                new StatViewServlet(), "/druid/*");
        // 白名單(為空表示,所有的都可以訪問,多個IP的時候用逗號隔開)
        servletRegistrationBean.addInitParameter("allow", "127.0.0.1");
        // IP黑名單 (存在共同時,deny優先於allow) (黑白名單就是如果是黑名單,那么該ip無法登陸該可視化界面)
        servletRegistrationBean.addInitParameter("deny", "127.0.0.2");
        // 設置登錄的用戶名和密碼
        servletRegistrationBean.addInitParameter("loginUsername", "root");
        servletRegistrationBean.addInitParameter("loginPassword", "123456");
        // 是否能夠重置數據.
        servletRegistrationBean.addInitParameter("resetEnable", "false");
        return servletRegistrationBean;
    }

    @Bean
    public FilterRegistrationBean druidStatFilter() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(
                new WebStatFilter());
        // 添加過濾規則
        filterRegistrationBean.addUrlPatterns("/*");
        // 添加不需要忽略的格式信息
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        System.out.println("druid初始化成功!");
        return filterRegistrationBean;

    }
}

這里說明幾點

(1)登陸地址:http://127.0.0.1:8080/druid/index.html(端口號看自己設置的端口號)
(2)一旦配置黑名單,那么該ip訪問是沒有權限的登陸的
(3)如果想看SQL執行結果,那么上面數據源配置一定要添加dataSource.setFilters(filters),我之前就沒有添加,所以其它都能正常使用,就是無法監控Sql語句。

效果圖

確實很好用。順便講下,我遇到其它功能都有用,唯獨Sql語句無法監控的問題,之后看界面才看出端倪來。

我發現界面中,filter類名為空,可是在yml確實配置了filters,怎么還是空,原因是數據源里沒有配置setFilters(filters)


文獻資料

1、 阿里github有關Druid結合Boot文檔
2、 demo參考github地址: (感謝作者分享)
3、 數據連接池的屬性字段說明
4、 yml配置、properties配置、ssm配置


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM