- 投稿日:2021-01-28T19:30:56+09:00
【Java(Spring Boot)】@〇〇Mappingを理解する
プログラミング勉強日記
2021年1月28日
昨日の記事で@RequestBody
について扱った。Spring Bootの@〇〇Mapping
についてちゃんと理解していなかったので、それぞれ理解する。〇〇Mappingとは
簡単に言うと、コントローラクラスの
@〇〇Mapping
はどんな場所なのか知らせてくれるものである。〇〇Mappingのあとの""
部分はそのURLにリクエストあったときにそれぞれの処理が行われる
@RequestMapping
の役割全体処理の入り口のようなもの。ここを通ることでいろいろな処理にいくことができる。
@GetMapping
の役割文字通りGET(取得)の役割を果たす部分。登録されているデータを取ってくる。
@PostMapping
の役割文字通りPOST(投稿)の役割を果たす部分。新しいデータ登録などをする。
@DeleteMapping
の役割文字通りDELETE(削除)の役割を果たす部分。既存データを削除する。
@PutMapping
の役割更新の役割を果たす部分。既存データや情報を上書きする。
- 投稿日:2021-01-28T17:31:18+09:00
mavenを使用して依存関係のあるjarファイルを一括ダウンロードする方法
mavenを使用して依存関係のあるjarファイルをダウンロードする方法を紹介します。
環境
- Windows
- apache-maven-3.6.2
1. mavenプロジェクトを作成
mavenプロジェクトを作成するディレクトリへ移動します。
(ここでは「C:\Data\mvn_project」配下に作成します。)c:>cd c:\data\mvn_project c:\Data\mvn_project>以下のコマンドでmavenプロジェクトを作成します。
mvn archetype:generate -DgroupId=com.sample -DartifactId=test -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
c:\Data\mvn_project>mvn archetype:generate -DgroupId=com.sample -DartifactId=test -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false [INFO] Scanning for projects... [INFO] [INFO] ------------------< org.apache.maven:standalone-pom >------------------- [INFO] Building Maven Stub Project (No POM) 1 [INFO] --------------------------------[ pom ]--------------------------------- [INFO] [INFO] >>> maven-archetype-plugin:3.1.2:generate (default-cli) > generate-sources @ standalone-pom >>> [INFO] [INFO] <<< maven-archetype-plugin:3.1.2:generate (default-cli) < generate-sources @ standalone-pom <<< [INFO] [INFO] [INFO] --- maven-archetype-plugin:3.1.2:generate (default-cli) @ standalone-pom--- [INFO] Generating project in Batch mode [INFO] ------------------------------------------------------------------------- --- [INFO] Using following parameters for creating project from Old (1.x) Archetype: maven-archetype-quickstart:1.0 [INFO] ---------------------------------------------------------------------------- [INFO] Parameter: basedir, Value: c:\Data\mvn_project [INFO] Parameter: package, Value: com.sample [INFO] Parameter: groupId, Value: com.sample [INFO] Parameter: artifactId, Value: test [INFO] Parameter: packageName, Value: com.sample [INFO] Parameter: version, Value: 1.0-SNAPSHOT [INFO] project created from Old (1.x) Archetype in dir: c:\Data\mvn_project\test [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 29.821 s [INFO] Finished at: 2021-01-28T16:59:41+09:00 [INFO] ------------------------------------------------------------------------ c:\Data\mvn_project>
dir
コマンドで「test」ディレクトリが作成されていることを確認します。c:\Data\mvn_project>dir ドライブ C のボリューム ラベルは Windows です ボリューム シリアル番号は F039-627E です c:\Data\mvn_project のディレクトリ 2021/01/28 16:59 <DIR> . 2021/01/28 16:59 <DIR> .. 2021/01/28 16:59 <DIR> test 0 個のファイル 0 バイト 3 個のディレクトリ 159,863,459,840 バイトの空き領域 c:\Data\mvn_project>cd test c:\Data\mvn_project\test>dir ドライブ C のボリューム ラベルは Windows です ボリューム シリアル番号は F039-627E です c:\Data\mvn_project\test のディレクトリ 2021/01/28 16:59 <DIR> . 2021/01/28 16:59 <DIR> .. 2021/01/28 16:59 649 pom.xml 2021/01/28 16:59 <DIR> src 1 個のファイル 649 バイト 3 個のディレクトリ 159,863,328,768 バイトの空き領域 c:\Data\mvn_project\test>2. pom.xml に依存関係を追加
「c:\Data\mvn_project\test」配下のpom.xmlに、依存関係を追加します。
ここでは「Spring Web MVC 5.3.3」で必要なjarファイルをダウンロードします。
mavenリポジトリで依存関係を確認します。
依存関係<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.3</version> </dependency>「pom.xml」に上記の「依存関係」を追加します。
c<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.sample</groupId> <artifactId>test</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>test</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> </project>c<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.sample</groupId> <artifactId>test</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>test</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <!-- 追加 --> <groupId>org.springframework</groupId> <!-- 追加 --> <artifactId>spring-webmvc</artifactId> <!-- 追加 --> <version>5.3.3</version> <!-- 追加 --> </dependency> <!-- 追加 --> </dependencies> </project>3. jarファイル一括ダウンロード
以下のコマンドで「Spring Web MVC 5.3.3」で必要なjarファイルを一括ダウンロードします。
mvn dependency:copy-dependencies -DoutputDirectory=lib
(-DoutputDirectory
でダウンロード先に「lib」ディレクトリを指定)c:\Data\mvn_project\test>mvn dependency:copy-dependencies -DoutputDirectory=lib [INFO] Scanning for projects... [INFO] [INFO] --------------------------< com.sample:test >--------------------------- [INFO] Building test 1.0-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- Downloading from central: https://repo.maven.apache.org/maven2/org/springframework/spring-webmvc/5.3.3/spring-webmvc-5.3.3.pom Downloaded from central: https://repo.maven.apache.org/maven2/org/springframework/spring-webmvc/5.3.3/spring-webmvc-5.3.3.pom (2.9 kB at 2.3 kB/s) Downloading from central: https://repo.maven.apache.org/maven2/org/springframework/spring-aop/5.3.3/spring-aop-5.3.3.pom Downloaded from central: https://repo.maven.apache.org/maven2/org/springframework/spring-aop/5.3.3/spring-aop-5.3.3.pom (2.2 kB at 6.0 kB/s) Downloading from central: https://repo.maven.apache.org/maven2/org/springframework/spring-beans/5.3.3/spring-beans-5.3.3.pom Downloaded from central: https://repo.maven.apache.org/maven2/org/springframework/spring-beans/5.3.3/spring-beans-5.3.3.pom (2.0 kB at 5.6 kB/s) Downloading from central: https://repo.maven.apache.org/maven2/org/springframework/spring-core/5.3.3/spring-core-5.3.3.pom Downloaded from central: https://repo.maven.apache.org/maven2/org/springframework/spring-core/5.3.3/spring-core-5.3.3.pom (2.0 kB at 5.6 kB/s) Downloading from central: https://repo.maven.apache.org/maven2/org/springframework/spring-jcl/5.3.3/spring-jcl-5.3.3.pom Downloaded from central: https://repo.maven.apache.org/maven2/org/springframework/spring-jcl/5.3.3/spring-jcl-5.3.3.pom (1.8 kB at 5.0 kB/s) Downloading from central: https://repo.maven.apache.org/maven2/org/springframework/spring-context/5.3.3/spring-context-5.3.3.pom Downloaded from central: https://repo.maven.apache.org/maven2/org/springframework/spring-context/5.3.3/spring-context-5.3.3.pom (2.6 kB at 7.5 kB/s) Downloading from central: https://repo.maven.apache.org/maven2/org/springframework/spring-expression/5.3.3/spring-expression-5.3.3.pom Downloaded from central: https://repo.maven.apache.org/maven2/org/springframework/spring-expression/5.3.3/spring-expression-5.3.3.pom (2.1 kB at 5.6 kB/s) Downloading from central: https://repo.maven.apache.org/maven2/org/springframework/spring-web/5.3.3/spring-web-5.3.3.pom Downloaded from central: https://repo.maven.apache.org/maven2/org/springframework/spring-web/5.3.3/spring-web-5.3.3.pom (2.2 kB at 5.9 kB/s) Downloading from central: https://repo.maven.apache.org/maven2/org/springframework/spring-webmvc/5.3.3/spring-webmvc-5.3.3.jar Downloading from central: https://repo.maven.apache.org/maven2/org/springframework/spring-core/5.3.3/spring-core-5.3.3.jar Downloading from central: https://repo.maven.apache.org/maven2/org/springframework/spring-context/5.3.3/spring-context-5.3.3.jar Downloading from central: https://repo.maven.apache.org/maven2/org/springframework/spring-beans/5.3.3/spring-beans-5.3.3.jar Downloading from central: https://repo.maven.apache.org/maven2/org/springframework/spring-aop/5.3.3/spring-aop-5.3.3.jar Downloaded from central: https://repo.maven.apache.org/maven2/org/springframework/spring-aop/5.3.3/spring-aop-5.3.3.jar (374 kB at 148 kB/s) Downloading from central: https://repo.maven.apache.org/maven2/org/springframework/spring-jcl/5.3.3/spring-jcl-5.3.3.jar Downloaded from central: https://repo.maven.apache.org/maven2/org/springframework/spring-jcl/5.3.3/spring-jcl-5.3.3.jar (24 kB at 8.1 kB/s) Downloading from central: https://repo.maven.apache.org/maven2/org/springframework/spring-expression/5.3.3/spring-expression-5.3.3.jar Downloaded from central: https://repo.maven.apache.org/maven2/org/springframework/spring-webmvc/5.3.3/spring-webmvc-5.3.3.jar (996 kB at 272 kB/s) Downloading from central: https://repo.maven.apache.org/maven2/org/springframework/spring-web/5.3.3/spring-web-5.3.3.jar Downloaded from central: https://repo.maven.apache.org/maven2/org/springframework/spring-beans/5.3.3/spring-beans-5.3.3.jar (696 kB at 182 kB/s) Downloaded from central: https://repo.maven.apache.org/maven2/org/springframework/spring-expression/5.3.3/spring-expression-5.3.3.jar (283 kB at 59 kB/s) Downloaded from central: https://repo.maven.apache.org/maven2/org/springframework/spring-context/5.3.3/spring-context-5.3.3.jar (1.2 MB at 240 kB/s) Downloaded from central: https://repo.maven.apache.org/maven2/org/springframework/spring-web/5.3.3/spring-web-5.3.3.jar (1.6 MB at 179 kB/s) Downloaded from central: https://repo.maven.apache.org/maven2/org/springframework/spring-core/5.3.3/spring-core-5.3.3.jar (1.5 MB at 154 kB/s) [INFO] [INFO] --- maven-dependency-plugin:2.8:copy-dependencies (default-cli) @ test -- - [INFO] Copying spring-webmvc-5.3.3.jar to c:\Data\mvn_project\test\lib\spring-webmvc-5.3.3.jar [INFO] Copying junit-3.8.1.jar to c:\Data\mvn_project\test\lib\junit-3.8.1.jar [INFO] Copying spring-jcl-5.3.3.jar to c:\Data\mvn_project\test\lib\spring-jcl-5.3.3.jar [INFO] Copying spring-beans-5.3.3.jar to c:\Data\mvn_project\test\lib\spring-beans-5.3.3.jar [INFO] Copying spring-context-5.3.3.jar to c:\Data\mvn_project\test\lib\spring-context-5.3.3.jar [INFO] Copying spring-core-5.3.3.jar to c:\Data\mvn_project\test\lib\spring-core-5.3.3.jar [INFO] Copying spring-aop-5.3.3.jar to c:\Data\mvn_project\test\lib\spring-aop-5.3.3.jar [INFO] Copying spring-expression-5.3.3.jar to c:\Data\mvn_project\test\lib\spring-expression-5.3.3.jar [INFO] Copying spring-web-5.3.3.jar to c:\Data\mvn_project\test\lib\spring-web-5.3.3.jar [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 31.649 s [INFO] Finished at: 2021-01-28T17:22:24+09:00 [INFO] ------------------------------------------------------------------------ c:\Data\mvn_project\test>「
lib
」ディレクトリ配下を確認します。c:\Data\mvn_project\test>cd lib c:\Data\mvn_project\test\lib>dir ドライブ C のボリューム ラベルは Windows です ボリューム シリアル番号は F039-627E です c:\Data\mvn_project\test\lib のディレクトリ 2021/01/28 17:22 <DIR> . 2021/01/28 17:22 <DIR> .. 2021/01/28 17:22 121,070 junit-3.8.1.jar 2021/01/28 17:22 374,340 spring-aop-5.3.3.jar 2021/01/28 17:22 695,878 spring-beans-5.3.3.jar 2021/01/28 17:22 1,243,858 spring-context-5.3.3.jar 2021/01/28 17:22 1,467,336 spring-core-5.3.3.jar 2021/01/28 17:22 282,517 spring-expression-5.3.3.jar 2021/01/28 17:22 23,943 spring-jcl-5.3.3.jar 2021/01/28 17:22 1,565,794 spring-web-5.3.3.jar 2021/01/28 17:22 996,262 spring-webmvc-5.3.3.jar 9 個のファイル 6,770,998 バイト 2 個のディレクトリ 159,838,789,632 バイトの空き領域 c:\Data\mvn_project\test\lib>「
spring-webmvc-5.3.3.jar
」とそれに必要なjarファイルがダウンロードされていることが確認できます。
以上
- 投稿日:2021-01-28T17:12:09+09:00
List<Integer>の中身を文字列で結合する
業務で使用した場面
同様の場面に2度遭遇して、1回目の時どうやって実装したっけ?となったので、記録
リストのが持っている社員番号を、SQLのwhere句で使用するため、カンマで区切った文字列を作成し、
where emp_no in (作成した文字列)
を実装する。StringJoinPractise.javapublic static void main(String[] args) { List <Integer> empNosInt = new ArrayList<>(); empNosInt.add(1); empNosInt.add(3); empNosInt.add(6); empNosInt.add(10); List <String> empNosStr = new ArrayList<>(); for (Integer empNo : empNosInt) { empNosStr.add(String.valueOf(empNo)); } String empNosString = String.join(",", empNosStr); System.out.println(empNosString); } //出力 //1,3,6,10
- 投稿日:2021-01-28T14:17:31+09:00
Apache Camel で `transacted()` と `split()` を組み合わせた際に StackOverflowError
概要
Apache Camel でDBから読み取ったレコードをループ処理したところ、1000件近いデータは処理できず StackOverflowError が発生した。
調べていくと、
split()
でループさせるだけなら問題ないが、それがtransacted()
より後である場合に発生することがわかった。うまい解決ができていないが、再現と回避のために試したことをまとめておく。
回避策の案
- JVMのスタックサイズを増やす
- お手軽、コード変更は不要
- データが増えれば結局 StackOverflowError が発生する
- ループ内を別スレッドで処理する
- 変更は1〜2行で済む
- トランザクションから外れるので、DBを読み書きしているような処理では採用できない
split()
を多重にして、一段あたりのループ回数を抑える
- ループ内の処理も合わせて修正する必要がある
- データが増えれば結局 StackOverflowError が発生する
(とはいえ1重で800回だったのなら、3重で1500万回のループには耐えられる見込み1)テスト環境
以前に勉強用に作ったサンプルを流用したため、環境も同じ。
https://qiita.com/HMMNRST/items/da89ce94c203633a8fb3
- Java: 1.8.0_191
- Maven: 3.6.3
- Camel: 3.2.0
- Spring: 5.2.5.RELEASE
- Spring Boot: 2.2.6.RELEASE
- MySQL: 5.7.30
単純な再現例
長さ1万の配列をループ処理するだけのrouteを作って実験してみる。
以下のコードでは、進捗を見れるようにループの中で時々インデックスを出力している2。
src/main/java/org/example/mycamelapp/routes/SampleRoute.java@Component public class SampleRoute extends RouteBuilder { @Override public void configure() throws Exception { from("timer:sample?repeatCount=1") .transacted() .split(constant(new int[10000])) .process(exchange -> { int index = exchange.getProperty(Exchange.SPLIT_INDEX, Integer.class); if ((index & (index - 1)) == 0) System.out.println(index); }) .end() .log("transaction finished.") ; } }JVMのスタックサイズを指定して実行する。(
-Xss
オプション)terminalcd path/to/app # create JAR file mvn clean package spring-boot:repackage # run (send SIGINT after 20 seconds) timeout -sINT 20s \ java -Xss256k -jar target/mycamelapp-1.0-SNAPSHOT.jar手元の環境では、スタックサイズ256KBだとループ140回程度、1MB(デフォルト)だと800回程度、4MBだと3000回程度で
StackOverflowError
が発生した。16MBなら1万回は大丈夫だった。一方で、
.transacted()
を消した場合は256KBでも問題なく処理できた。スタックトレースの確認
camel の内部のソースコードを理解するのは難しいが、どういう動作でエラーが発生したか確認しておく。ループ中の
StackOverflowError
なので、恐らく再帰的な呼び出しになっていると予想はつく。実際、以下の部分が再帰になっていた。
Stack Trace Source Code (3.2.0) ... ... CamelInternalProcessor.process() CamelInternalProcessor.java:286 MulticastProcessor\$MulticastState.lambda\$run\$1() MulticastProcessor.java:364 AsyncCompletionService\$Task.run() AsyncCompletionService.java:150 DefaultReactiveExecutor\$Worker.schedule() DefaultReactiveExecutor.java:148 DefaultReactiveExecutor.schedule() DefaultReactiveExecutor.java:55 CamelInternalProcessor\$AsyncAfterTask.done() CamelInternalProcessor.java:186 TransactionErrorHandler.process() TransactionErrorHandler.java:126 CamelInternalProcessor.process() CamelInternalProcessor.java:286
.transacted()
を消した場合のスタックトレースも見てみたが、もっと根元に近い部分からメソッド呼び出しが変わっていて、うまく比較できなかった。エラー回避策(欠点あり)
.split()
に使える設定を眺めていたところ、並列処理にしてループの度にスレッドを分ければいいのではないかと思いついた。スレッドプールの指定もできるので3、処理順序を保つ必要があるなら1スレッドだけ割り当てればいい。diff.split(constant(new int[10000])) + .parallelProcessing() + .executorService(Executors.newSingleThreadExecutor()) + .process(exchange -> {
スレッドを分けるオーバーヘッドのためか、処理は遅くなる。ループ内部の処理時間が十分長ければ気にしなくていいと思う。(未確認)
もっと重大な問題について次節で扱う。
DBの絡む例
「スレッドを別にした場合、DBのトランザクションは共有されるのか?」という不安が浮かんだので、もう少し複雑にしたrouteで実験する。
ループの外でDBレコードを作成し、中で取得する。同じトランザクションでないとこの新規レコードは見えない。
src/main/java/org/example/mycamelapp/routes/SampleRoute.java@Component public class SampleRoute extends RouteBuilder { @Override public void configure() throws Exception { from("timer:sample?repeatCount=1") .transacted() // create a new task and get its ID .to("sql:INSERT INTO task () VALUES ()") .to("sql:SELECT LAST_INSERT_ID()?outputType=SelectOne") .setHeader("task_id", body()) .setBody(constant(new int[10000])) .split(body()) .parallelProcessing() // BAD!! // get the task .to("sql:SELECT * FROM task WHERE task_id = #:task_id?outputType=SelectOne") // (debug) .process(exchange -> { int index = exchange.getProperty(Exchange.SPLIT_INDEX, Integer.class); if ((index & (index - 1)) == 0) System.out.printf("index: %d, body: %s%n", index, exchange.getIn().getBody()); }) .end() .log("transaction finished.") ; } }これを実行すると、SELECT文でレコードを取得できていない(nullになっている)ことがわかる。
.parallelProcessing()
を消した場合はレコードを取得できる(が StackOverflowError になる)。エラー回避策(第2案)
他にも色々と試していたところ、再帰処理は
split()
が終わる(対応するend()
を抜ける)と完了することがわかった。これはループのネストは問題になりにくいことを示している4。ならば現在1重のループを敢えて多重に変形すると解決するかもしれない。このためには、
split()
に渡すデータを分割しなければいけない。 ruby でいう#each_slice
みたいなことをしたいのだが、 camel に適切なものがあるか分からなかったので、類似のメソッドtokenize()
を参考に自作した。src/main/java/org/example/mycamelapp/routes/SampleRoute.java@Component public class SampleRoute extends RouteBuilder { @Override public void configure() throws Exception { from("timer:sample?repeatCount=1") .transacted() // create a new task and get its ID .to("sql:INSERT INTO task () VALUES ()") .to("sql:SELECT LAST_INSERT_ID()?outputType=SelectOne") .setHeader("task_id", body()) .setBody(constant(new int[10000])) .split(group(body(), 1000)) .split(group(body(), 100)) .split(body()) // get the task .to("sql:SELECT * FROM task WHERE task_id = :#task_id?outputType=SelectOne") // (debug) .process(exchange -> { int index = exchange.getProperty(Exchange.SPLIT_INDEX, Integer.class); if ((index & (index - 1)) == 0) System.out.printf("index: %d, body: %s%n", index, exchange.getIn().getBody()); }) .end() .end() .end() .log("transaction finished.") ; } // org.apache.camel.support.builder.* public static ValueBuilder group(ValueBuilder builder, int group) { return new ValueBuilder(ExpressionBuilder.groupIteratorExpression( builder.getExpression(), null, "" + group, false )); } }ループを 100 * 10 * 10 ≧ 10000 に分けたので、スタックの消費は 100 + 10 + 10 = 120 程度で済む。実際このコードはスタックサイズ256KB(元々は140回が限界)でもエラーにならなかった。
※ 3重なら3乗根が最もスタックを節約できるこの例ではループの中は修正していないが、
Exchange.SPLIT_INDEX
の値は一番内側のループのカウントなので、元と異なるログ出力になっている。他にもループを多重化したことへの対応が必要になるパターンは多いと思われる。参考
- Camel のドキュメント
- Camel のソースコード
transacted()
とsplit()
の組み合わせに関する質問
- 投稿日:2021-01-28T14:10:33+09:00
Java リフレクションでJAR実行
JavaでJARリフレクションを実行した際の備忘録
サンプルソースのみ// JarFile のパス String strPathJar = "D:\\pleiades\\zz_orgBatch\\test\\testReflect.jar"; // 実行するクラスとメソッド String strLoadClass = "src.batch.test.TestBatch"; String strMethod = "startBatch"; // 対象JARファイルを指定 File jarFile = new File(strPathJar); URLClassLoader loader = URLClassLoader.newInstance(new URL[] {jarFile.toURI().toURL()}); // クラスをロード Class<?> c = loader.loadClass(strLoadClass); //インスタンス化 Object obj = c.getDeclaredConstructor().newInstance(); // 実行するメソッドと引数を定義する Method m1 = c.getMethod(strMethod,String[].class); //引数をオブジェクト化する必要がある String[] strParam = {}; Object[] objParam = new Object[] {strParam}; // 実行 m1.invoke(obj,objParam);
- 投稿日:2021-01-28T13:58:06+09:00
WebSphereでハングの可能性のあるスレッドが通知されたとき(WSVR0605W)
概要
- WebSphere Application Server(WAS)には、ハングの可能性を検知してログに出力する機能がある
- しきい値に設定した時間を超える処理時間がかかっている場合に、SystemOut.logにログが出力される
- 通常の処理完了時間の範囲を見積もり、そこからしきい値を設定すべき
- あくまでも検知するのは「ハングの可能性」である。実際にハングが発生しているとは限らない
ハングとは?
下記のような原因で発生する、システムの機能低下の状態。
自然解消せず、利用者や監視ツールにより発見されるまで、そのままの状態が継続してしまうこともある。
- 無限ループなどの単純なソフトウェアの障害
- リソース・デッドロックやリソースの取得待ちなどの外部リソースとの接続上の障害
検出時の SystemOut.log のメッセージの例
[11/08/10 15:55:33:746 JST] 890e8c75 ThreadMonitor W WSVR0605W: スレッド "Servlet.Engine.Transports : 1293" (2ca38c77) が 612,791 ミリ秒間アクティブで、ハングしている可能性があります。サーバー内には、ハングの可能性のあるスレッドが合計 1 本あります引用元: WebSphere Application Server構築・運用バイブル【WAS8.5/8.0/7.0対応】 409ページ
どのように対処すべきか
利用しているアプリケーションにおいて、該当の処理が通常の処理時間内なのか、異常な処理時間と言えるのかを確認する。
通常の処理時間である場合
ハング検出ポリシーの構成 (English: Configuring the hang detection policy) を見直し、誤検知されないように設定値を修正する。
異常な処理時間である場合
外部リソースとの接続(コネクションプールなど)の設定値の見直しをしたり、アプリケーションの改修を検討する。
- 投稿日:2021-01-28T11:52:28+09:00
spring-bootのDynamicPropertyRegistryでtest時に動的にプロパティ変更
src/main/resources/application.propertiessample.value=sampleimport org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.DynamicPropertyRegistry; import org.springframework.test.context.DynamicPropertySource; @SpringBootTest class DynamicPropertySourceTest { @DynamicPropertySource static void registerProperties(DynamicPropertyRegistry registry) { registry.add("sample.value", () -> "dynamic sample value."); } @Value("${sample.value}") String value; @Test void test() { System.out.println(value); //dynamic sample value.と表示 } }これの主な使いどころは、ユニットテストの外部で起動するものに依存する場合に使用する。たとえば、 https://www.baeldung.com/spring-dynamicpropertysource にあるとおりTestcontainersとの組み合わせで用いる。dockerで起動したコンテナからポートとかJDBC URLとかを取得してspring-bootのプロパティとして指定する。
- 投稿日:2021-01-28T00:31:54+09:00
Javaの時分(hhmm)をバリデーションする方法
経緯
Javaの日付フォーマットの確認方法はぐぐるといくつか出てくるのだが、「1900」や「11:00」など時分形式のバリデーションはいろいろ調べてもあまり出てこなかった。
ちなみに日付のフォーマット確認はSimpleDateFormatなどを利用すればできる。
https://www.sejuku.net/blog/20994正規表現で調べる方法はいくつか見つかったが、できれば同じようにフォーマッターなどを使用して確認をしたい。
https://www.saka-en.com/java/java-time-check/方法
DateTimeFormatterを使ってExceptionに入るかどうかで判定すれば時分(hhmm)形式でもできそうだった。
以下のような形で実装する。import java.time.format.DateTimeParseException; import java.time.format.DateTimeFormatter; import java.time.LocalTime; public boolean checkDateTimeFormat(final String format, final String value) { try { LocalTime.parse(value, DateTimeFormatter.ofPattern(format)); } catch (DateTimeParseException e) { return false; } return true; } checkDateTimeFormat("HHmm", "1900");誤りなどあればご指摘もらえますと幸いです。