かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

Spring Boot 1.5.x の Web アプリを 2.0.x へバージョンアップする ( その11 )( HikariCP のコネクションプーリングの情報を JMX で取得できるようにする )

概要

記事一覧はこちらです。

Spring Boot 1.5.x の Web アプリを 2.0.x へバージョンアップする ( その10 )( Tomcat connection Pool → HikariCP に変更する ) の続きです。

参照したサイト・書籍

目次

  1. spring.datasource.hikari.register-mbeans=true の設定がなくても HikariCP が MBean に登録されることを確認する
  2. Pool(HikariPool-1)、PoolConfig(HikariPool-1)で MBean に登録されるようにする
  3. clean タスク実行 → Rebuild Project 実行 → build タスクを実行する
  4. ユニットテスト実行時には MBeanExporter の bean が生成されないのか?
  5. ApplicationConfig.java を変更してユニットテスト実行時には mBeanExporter.addExcludedBean("dataSource"); を呼び出さないようにする
  6. 再度 clean タスク実行 → Rebuild Project 実行 → build タスクを実行する

手順

spring.datasource.hikari.register-mbeans=true の設定がなくても HikariCP が MBean に登録されることを確認する

Spring が起動時に MBean を登録するのであれば spring.datasource.hikari.register-mbeans=true の設定がなくても登録されてしまうのだろうか?と思ったので試してみます。

src/main/resources/application.properties で spring.datasource.hikari.register-mbeans=trueコメントアウトしてから、

spring.autoconfigure.exclude=com.integralblue.log4jdbc.spring.Log4jdbcAutoConfiguration
spring.datasource.hikari.jdbc-url=jdbc:postgresql://localhost/ksbylending
spring.datasource.hikari.username=ksbylending_user
spring.datasource.hikari.password=xxxxxxxx
spring.datasource.hikari.driver-class-name=org.postgresql.Driver
spring.datasource.hikari.leak-detection-threshold=5000
#spring.datasource.hikari.register-mbeans=true
  • com.integralblue.log4jdbc.spring.Log4jdbcAutoConfiguration を無効にしないと dataSource ではなく Pool(HikariPool-1)という名前で MBean に登録されるので、spring.autoconfigure.exclude=com.integralblue.log4jdbc.spring.Log4jdbcAutoConfiguration の設定を一時的に入れています。

IntelliJ IDEA から Tomcat を起動 → ログイン画面(http://localhost:8080/)からログイン → jconsole で確認してみると、dataSource という名前の MBean が登録されていました。spring.datasource.hikari.register-mbeans=true を設定がなくても Spring Boot の AutoConfiguration によって登録されるようです。

f:id:ksby:20181019040547p:plain

spring.datasource.hikari.register-mbeans=trueコメントアウトしていたのは元に戻します。

Pool(HikariPool-1)、PoolConfig(HikariPool-1)で MBean に登録されるようにする

src/main/java/ksbysample/webapp/lending/config/ApplicationConfig.java を以下のように変更します。

@Configuration
public class ApplicationConfig {

    private final ConnectionFactory connectionFactory;

    private final MessageSource messageSource;

    private final MBeanExporter mBeanExporter;

    /**
     * @param connectionFactory {@link ConnectionFactory} bean
     * @param messageSource     {@link MessageSource} bean
     * @param mBeanExporter     {@link MBeanExporter} bean
     */
    public ApplicationConfig(ConnectionFactory connectionFactory
            , MessageSource messageSource
            , MBeanExporter mBeanExporter) {
        this.connectionFactory = connectionFactory;
        this.messageSource = messageSource;
        this.mBeanExporter = mBeanExporter;
    }

    ..........

    /**
     * @return HikariCP の DataSource オブジェクト
     */
    @Bean
    @ConfigurationProperties("spring.datasource.hikari")
    public DataSource dataSource() {
        mBeanExporter.addExcludedBean("dataSource");
        return DataSourceBuilder.create()
                .type(HikariDataSource.class)
                .build();
    }
  • private final MBeanExporter mBeanExporter; を追加し、コンストラクタインジェクションされるようコンストラクタに処理を追加します。
  • dataSource Bean 内に mBeanExporter.addExcludedBean("dataSource"); を追加し、Spring Boot により dataSource という名前で MBean に登録されないようにします。

動作確認してみます。src/main/resources/application.properties は以下の設定になっており、

spring.autoconfigure.exclude=com.integralblue.log4jdbc.spring.Log4jdbcAutoConfiguration
spring.datasource.hikari.jdbc-url=jdbc:postgresql://localhost/ksbylending
spring.datasource.hikari.username=ksbylending_user
spring.datasource.hikari.password=xxxxxxxx
spring.datasource.hikari.driver-class-name=org.postgresql.Driver
spring.datasource.hikari.leak-detection-threshold=5000
spring.datasource.hikari.register-mbeans=true

IntelliJ IDEA から Tomcat を起動 → ログイン画面(http://localhost:8080/)からログイン → jconsole で確認してみると、今度は Pool(HikariPool-1)、PoolConfig(HikariPool-1)で MBean に登録されています。

f:id:ksby:20181019044357p:plain

clean タスク実行 → Rebuild Project 実行 → build タスクを実行する

clean タスク → Rebuild Project → build タスクを実行してみます。

f:id:ksby:20181020091103p:plain .......... f:id:ksby:20181020091206p:plain

checkstyle で2点警告が出たのと、

  • Member name 'mBeanExporter' must match pattern '^[a-z][a-z0-9][a-zA-Z0-9]*$'. [MemberName]
  • Parameter name 'mBeanExporter' must match pattern '^[a-z]([a-z0-9][a-zA-Z0-9]*)?$'. [ParameterName]

テストも大量に失敗しました。。。 Project Tool Window で src/test を選択した後、コンテキストメニューを表示して「Run」-「All Tests」を選択して IntelliJ IDEA からテストを実行してみます。

f:id:ksby:20181020092429p:plain

失敗しているテストを見ると Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.jmx.export.MBeanExporter' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} というエラーが発生していました。どうもテストだと MBeanExporter の bean が生成されていないようです。

ユニットテスト実行時には MBeanExporter の bean が生成されないのか?

ユニットテストではなく通常 Tomcat を起動する時に生成される MBeanExporter の bean は org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration の mbeanExporter メソッドで生成されますが(このメソッド内に breakpoint を設定して Tomcat を起動すると止まります)、

f:id:ksby:20181020220839p:plain

ただし、例えば src/test/groovy/ksbysample/webapp/lending/SampleHelperTest.groovy のテストを実行した時には、このメソッド内に設定した breakpoint には止まりませんでした。確かにユニットテストの時には MBeanExporter の bean は生成されていないようです。

IntelliJ IDEA の Find in Path ダイアログで spring.jmx.enabled で検索してみると org.springframework.boot.test.context.SpringBootContextLoader#disableJmx というメソッドが見つかりました。

f:id:ksby:20181020220453p:plain

また org.springframework.boot.test.context.SpringBootContextLoader のクラスコメントを見ると @see SpringBootTest という記述があります。

f:id:ksby:20181020221411p:plain

この2つから以下の仕組みになっているようです。

  1. @SpringBootTest アノテーションが付加されたテストが実行されると org.springframework.boot.test.context.SpringBootContextLoader#disableJmx が呼び出される。
  2. spring.jmx.enabled=false が設定されるので、JmxAutoConfiguration クラスに付加されている条件 @ConditionalOnProperty(prefix = "spring.jmx", name = "enabled", havingValue = "true", matchIfMissing = true) と一致せず、mbeanExporter メソッドも実行されない(MBeanExporter の bean は生成されない)。

実際 org.springframework.boot.test.context.SpringBootContextLoader#disableJmx メソッド内に breakpoint を設定してから src/test/groovy/ksbysample/webapp/lending/SampleHelperTest.groovy のテストを実行すると設定した breakpoint で止まりました。

ApplicationConfig.java を変更してユニットテスト実行時には mBeanExporter.addExcludedBean("dataSource"); を呼び出さないようにする

src/main/java/ksbysample/webapp/lending/config/ApplicationConfig.java を以下のように変更します。

@Configuration
public class ApplicationConfig {

    private final ConnectionFactory connectionFactory;

    private final MessageSource messageSource;

    private final MBeanExporter mbeanExporter;

    /**
     * @param connectionFactory {@link ConnectionFactory} bean
     * @param messageSource     {@link MessageSource} bean
     * @param mbeanExporter     {@link MBeanExporter} bean
     */
    public ApplicationConfig(ConnectionFactory connectionFactory
            , MessageSource messageSource
            , @Autowired(required = false) MBeanExporter mbeanExporter) {
        this.connectionFactory = connectionFactory;
        this.messageSource = messageSource;
        this.mbeanExporter = mbeanExporter;
    }

    ..........

    /**
     * @return HikariCP の DataSource オブジェクト
     */
    @Bean
    @ConfigurationProperties("spring.datasource.hikari")
    public DataSource dataSource() {
        if (mbeanExporter != null) {
            mbeanExporter.addExcludedBean("dataSource");
        }
        return DataSourceBuilder.create()
                .type(HikariDataSource.class)
                .build();
    }
  • checkstyle の警告が出ないようにするために private final MBeanExporter mBeanExporter;private final MBeanExporter mbeanExporter; に変更します。
  • コンストラクタの引数を MBeanExporter mbeanExporter@Autowired(required = false) MBeanExporter mbeanExporter に変更します。
  • dataSource メソッドで mbeanExporter.addExcludedBean("dataSource"); を呼び出している部分を if (mbeanExporter != null) { ... } で囲みます。

再度 clean タスク実行 → Rebuild Project 実行 → build タスクを実行する

clean タスク → Rebuild Project → build タスクを実行してみると、今度は BUILD SUCCESSFUL が出力されました。

f:id:ksby:20181020224655p:plain

IntelliJ IDEA から Tomcat を起動 → ログイン画面(http://localhost:8080/)からログイン → jconsole で確認してみると、こちらも先程と同様に Pool(HikariPool-1)、PoolConfig(HikariPool-1)で MBean に登録されていました。

f:id:ksby:20181020224924p:plain

Spring Boot 2.0 から HikariCP がデフォルトになりましたが、MBean が絡むとなんか面倒です。。。

履歴

2018/10/19
初版発行。
2018/10/20
clean タスク実行 → Rebuild Project 実行 → build タスクを実行する 以降の記述を追加しました。