Spring Boot/マルチプロジェクト/共通処理のプロジェクト

Spring Boot/マルチプロジェクト/共通処理のプロジェクト

自身では実際には駆動せずに、共通処理だけをまとめておくプロジェクトの作り方。 起動する jar ではなく、単に読み込まれて利用されるだけの jar を最終的には生成するプロジェクト。

このような共通処理だけを実装するプロジェクトには特徴がある。

  • SpringBootApplication アノテーションをつけた起動の起点となるクラスが無い
  • application.properties や application.yml のような設定ファイルが無い
  • ↑の影響でテストの方法がやや特殊

サンプルを作っていく。親のPJの中に普通に STS の Spring Starter を使って1個子プロジェクトを作る。

SpringBootApplication アノテーションをつけた起動の起点となるクラスが無い

そのままだと、自動生成された、HogeHogeApplication みたいなクラスが出来ていると思うが完全に不要なので捨てる。

application.properties や application.yml のような設定ファイルが無い

これは、application.properties が1個のPJで1個という話で、それは依存先のPJのモノを使うという理由で無しのようだ。

なので消す。

build.gradle にビルドの設定を追記する

このような設定を build.gradle に追加する。

bootJar {
    enabled = false
}
 
jar {
    enabled = true
}

これは開発中は要らないのだが、ビルドの段階になって依存性のある対象から呼び出した場合それが存在しないよと言われるのでつけておく。

service を作る

共通処理ということで共通処理である service を実装してみる。 やや特殊な実装になる。

@Service
@EnableConfigurationProperties(HogeProperties.class)
public class HogeService {
    private final HogeProperties hogeProperties;
 
    public HogeService(HogeProperties hogeProperties) {
        this.hogeProperties = hogeProperties;
    }
 
    public String message() {
        return this.hogeProperties.getPiyo().getH1();
    }
}

普通の Service ではあるが設定値をコード中から後入れするためにコンストラクタインジェクションでそのクラスを受け取っている

ではこのクラスは何かというと実装がこうなる。

@ConfigurationProperties("hogehogehoge")
public class HogeProperties {
    private String h1;
    private String h2;
    private String h3;
 
    public String getH1() { return h1;}
    public void setH1(String h1) { this.h1 = h1; }
    public String getH2() { return h2; }
    public void setH2(String h2) { this.h2 = h2; }
    public String getH3() { return h3; }
    public void setH3(String h3) { this.h3 = h3; }
 
 
 
    public static class Piyo{
        private String p1;
        private String p2;
        private String p3;
        public String getP1() { return p1; }
        public void setP1(String p1) { this.p1 = p1; }
        public String getP2() { return p2; }
        public void setP2(String p2) { this.p2 = p2; }
        public String getP3() { return p3; }
        public void setP3(String p3) { this.p3 = p3; }
    }
    private Piyo piyo;
 
    public Piyo getPiyo() {
        return piyo;
    }
    public void setPiyo(Piyo piyo) {
        this.piyo = piyo;
    }
}

ConfigurationProperties というアノテーションを付けたいくつかのメンバとそれに対する getter, setter を持つクラスとなる。

このクラスは application.yml にすると、このような値を受け持つことを狙っている。

hogehogehoge:
  h1: "hello1"
  h2: "hello2"
  h3: "hello3"
  piyo:
    p1: "pello2"
    p2: "pello2"
    p3: "pello3"

先程の EnableConfigurationProperties で指定したクラスはこの値を引き込みたいという意図である。 実際に、application.yml を仮に作ってみると、ちゃんとこいつに値がマッピングされることがわかる。

service のテスト

実行のエントリーポイントが無いということはこの service を動作させるのはテストだけであるのでテストを作る

HogeServiceTest はこうなる。

@RunWith(SpringRunner.class)
@SpringBootTest({
    "hogehogehoge.piyo.h1=Hello1",
    "hogehogehoge.piyo.h2=Hello2"
})
public class HogeServiceTest {
    @Autowired
    private HogeService hogeService;
 
    @Test
    public void messageTest() {
        System.out.println(hogeService.message());
    }
 
    @SpringBootApplication
    public static class TestConfiguration {
    }
}

特別なのは Spring 自体を駆動するとっかかりのポイントが無いのでそれをダミーの内部クラスを作ってそこに SpringBootApplication を付与することで無理やり行っている。

そして、SpringBootTestアノテーションに設定値を書き込むことによって application.properties が無いことを補っている。

しかしヤヤ面倒。特に対象だけモロの設定はあるが、ライブラリが使う設定で、自分は使わないという設定もあるだろう。 ならばそれをプロファイルにしてやればいいのでは?

このプロファイル名を使う側から絶対に被らないモノにすれば成立する?

application-hogehogecoretest201812191606.yml を作って、このように指定する。

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("hogehogecoretest201812191606")
public class HogeServiceTest {

とりあえずコレでも動くようだ。

作った共通処理のプロジェクトを別のプロジェクトから使う

この共通処理プロジェクトと同階層に sample_batch プロジェクトがあったとして、それからどう使うか。

まず sample_batch プロジェクトの条件と整える。 まず sample_batch プロジェクトの setting.gradle を削除する。 これは共通の親まで行かないとプロジェクトが認識できないからである。 これで ベースプロジェクト の setting.gradle を参照するようになる。

ここで一発 build.gradle を駆動させておく。

次に共通で作った service を使う側の DI の管理下に入れるためにこのように書く。

@SpringBootApplication(scanBasePackages={"com.example.sample"})
public class SampleBatchApplication{

この書き方や書く理由はこちら参照。Spring Boot/マルチプロジェクト/違うパッケージのクラスをDIする 状況に合わせて書き分ける。

あとは普通に import して DI して使えばいいだけである。

application.yml を用意して、それを読み込ませればそのように動作することがわかる。

java/spring/spring_boot/multi_project/common_project.txt · 最終更新: 2019-07-02 11:09 by ore