とある地味なブログ

プログラミングとお絵かきに関する雑記。

@SpringBootApplicationがあるプロジェクトに依存するSpringBootApplicationの実行方法

Spring Bootアプリケーションには、普通、@SpringBootApplicationアノテーションのついたクラスが一つあると思う。

このプロジェクト(プロジェクトA)の機能を使う別のSpringBootApplication(プロジェクトB)を作りたいとする。

きれいなのは共通機能を別プロジェクトにする方法だと思うが、様々な要因からそうするしかなかった。

そうすると、プロジェクトBから見たとき、@SpringBootApplicationのついたクラスが二つになってしまう。

特にTomcat環境にデプロイする前提で開発しているとSpringBootServletInitializerの使用が必須だが、 これが複数クラスで使われていると不具合が出るようだ。

自分の環境ではSpring Securityを使っていたが、permitAllが効かずにすべてのページで認証が必要になったりした。

これを防ぐためには、プロジェクトBの@SpringBootApplicationを以下のように実装する。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;


@SpringBootApplication
@ComponentScan(basePackages = {
    "my.projectA",
    "my.projectB"
} , excludeFilters = {
    @Filter(type = FilterType.ASPECTJ, pattern = "my.projectA.controllers.*")
})
@EnableJpaRepositories(basePackages={"my.jpa.repository"})
@EntityScan(basePackages={"my.jpa.entity"})
public class MyWebApplication extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(MyWebApplication.class, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(MyWebApplication.class);
    }

}

JPAリポジトリを使用していない場合、@EnableJpaRepositories@EntityScanの行は必要ない。

今回、プロジェクトAのエンドポイントが必要なかっため、excludeFilters@Filter(type = FilterType.ASPECTJ, pattern = "my.projectA.controllers.*")を追加し、プロジェクトAのパスが生えないようにしている。

加えて、プロジェクトApom.xmlをコピーしたpom2.xmlを作成し、以下の修正をする。

<packaging>jar</packaging><packaging>war</packaging>

以下の箇所を削除する。

...
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>...</mainClass>
                    <layout>WAR</layout>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
...

さらに以下を追加する。

...
            <plugin>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.3.1</version>
                <executions>
                <execution>
                    <id>default-jar</id>
                    <phase>package</phase>
                    <goals>
                    <goal>jar</goal>
                    </goals>
                    <configuration>
                    <excludes>
                        <exclude>**/MyWebApplicationA.class</exclude>
                    </excludes>
                    </configuration>
                </execution>
                </executions>
            </plugin>
...

ここで、MyWebApplicationA@SpringBootApplicationアノテーション付きでSpringBootServletInitializerを継承したクラス。

参考: medium.com