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 に変更する ) の続きです。
- 今回の手順で確認できるのは以下の内容です。
- Spring Boot 1.5.x の Web アプリを 2.0.x へバージョンアップする ( その10 )( Tomcat connection Pool → HikariCP に変更する ) で dataSource という名前で JMX MBean に登録されると書きましたが、それだとコネクションプーリングの中で現在使用中のコネクション数(Active Connections)等が見られずやっぱり何か変だなと思っていろいろ調べてみたら、Spring Boot + HikariCPでコネクションプールのMetricsを取得する という記事を見つけました。なるほど、Spring Boot が起動時に MBean を登録してしまうんですね。。。
- 実装を修正して HikariCP のコネクションプーリングの情報を JMX から取得できるようにします。
参照したサイト・書籍
Spring Boot + HikariCPでコネクションプールのMetricsを取得する
https://matsumana.info/blog/2016/02/06/spring-boot-hikaricp-metrics/How to set @Autowired constructor params as “required=false” individually
https://stackoverflow.com/questions/42135102/how-to-set-autowired-constructor-params-as-required-false-individually
目次
spring.datasource.hikari.register-mbeans=true
の設定がなくても HikariCP が MBean に登録されることを確認する- Pool(HikariPool-1)、PoolConfig(HikariPool-1)で MBean に登録されるようにする
- clean タスク実行 → Rebuild Project 実行 → build タスクを実行する
- ユニットテスト実行時には MBeanExporter の bean が生成されないのか?
- ApplicationConfig.java を変更してユニットテスト実行時には
mBeanExporter.addExcludedBean("dataSource");
を呼び出さないようにする - 再度 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 によって登録されるようです。
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 に登録されています。
clean タスク実行 → Rebuild Project 実行 → build タスクを実行する
clean タスク → Rebuild Project → build タスクを実行してみます。
..........
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 からテストを実行してみます。
失敗しているテストを見ると 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 を起動すると止まります)、
ただし、例えば 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 というメソッドが見つかりました。
また org.springframework.boot.test.context.SpringBootContextLoader のクラスコメントを見ると @see SpringBootTest
という記述があります。
この2つから以下の仕組みになっているようです。
@SpringBootTest
アノテーションが付加されたテストが実行されると org.springframework.boot.test.context.SpringBootContextLoader#disableJmx が呼び出される。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 が出力されました。
IntelliJ IDEA から Tomcat を起動 → ログイン画面(http://localhost:8080/)からログイン → jconsole で確認してみると、こちらも先程と同様に Pool(HikariPool-1)、PoolConfig(HikariPool-1)で MBean に登録されていました。
Spring Boot 2.0 から HikariCP がデフォルトになりましたが、MBean が絡むとなんか面倒です。。。
履歴
2018/10/19
初版発行。
2018/10/20
clean タスク実行 → Rebuild Project 実行 → build タスクを実行する 以降の記述を追加しました。