20210128のJavaに関する記事は8件です。

【Java(Spring Boot)】@〇〇Mappingを理解する

プログラミング勉強日記

2021年1月28日
昨日の記事@RequestBodyについて扱った。Spring Bootの@〇〇Mappingについてちゃんと理解していなかったので、それぞれ理解する。

〇〇Mappingとは

 簡単に言うと、コントローラクラスの@〇〇Mappingはどんな場所なのか知らせてくれるものである。〇〇Mappingのあとの""部分はそのURLにリクエストあったときにそれぞれの処理が行われる

@RequestMappingの役割

 全体処理の入り口のようなもの。ここを通ることでいろいろな処理にいくことができる。

@GetMappingの役割

 文字通りGET(取得)の役割を果たす部分。登録されているデータを取ってくる。

@PostMappingの役割

 文字通りPOST(投稿)の役割を果たす部分。新しいデータ登録などをする。

@DeleteMappingの役割

 文字通りDELETE(削除)の役割を果たす部分。既存データを削除する。

@PutMappingの役割

 更新の役割を果たす部分。既存データや情報を上書きする。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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リポジトリで依存関係を確認します。

mvn_01.png

依存関係
<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ファイルがダウンロードされていることが確認できます。


以上

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

List<Integer>の中身を文字列で結合する

業務で使用した場面

同様の場面に2度遭遇して、1回目の時どうやって実装したっけ?となったので、記録
リストのが持っている社員番号を、SQLのwhere句で使用するため、カンマで区切った文字列を作成し、
where emp_no in (作成した文字列)を実装する。

StringJoinPractise.java
public 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
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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 オプション)

terminal
cd 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 の値は一番内側のループのカウントなので、元と異なるログ出力になっている。他にもループを多重化したことへの対応が必要になるパターンは多いと思われる。

参考


  1. 各段250回とすれば、全体のループは 250 ** 3 = 15625000回、スタック消費は 250 * 3 = 750 ( ≦ 800 )。 

  2. IDEで .process() のラムダ式内にブレークポイントを設置すれば、メッセージ処理を一時停止してスタックトレースの確認もできる。 

  3. スレッドプールを指定した場合は自動的に .parallelProcessing() もONになるので、両方指定する必要は無い。 

  4. 各ループ回数の掛け算でなく足し算で StackOverflowError になるかどうか決まるということ。 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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);
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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) を見直し、誤検知されないように設定値を修正する。

異常な処理時間である場合

外部リソースとの接続(コネクションプールなど)の設定値の見直しをしたり、アプリケーションの改修を検討する。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

spring-bootのDynamicPropertyRegistryでtest時に動的にプロパティ変更

src/main/resources/application.properties
sample.value=sample
import 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のプロパティとして指定する。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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");

誤りなどあればご指摘もらえますと幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む