最近、個人的にSpring Bootを使ったWebアプリケーション開発について学んでいます。ちょっとしたWebベースのアプリケーションをJavaで開発したいと思い、Spring Bootであればサクッと作れそうと思ったからです。。が、私自身Spring BootどころかSpringの知識さえも余りないので、「Spring徹底入門」や公式ドキュメント及びソースリーディングしながら、写経とデバッグで動きを追いながら、少しずつ動きや仕組みについて理解を進めているところです。
今回は、Spring BootでWebMvcベースのアプリケーション開発を行なう時、Javaベースのコンフィグレーションってどうするんだっけ?と、そもそも仕組み周りから理解できていなかったので整理してみました。
Auto-configuration
Spring Bootには、Auto-configurationという、最小限の設定でSpringアプリケーションを容易に構築できる仕組みがあります。例えば、必要な条件が満たされる場合(例えば特定のクラスがクラスパス上に存在しているまたは存在していない、など)にBean定義が有効になるといった具合です。以下は、CassandraAutoConfigurationクラスの一例で、アノテーション@ConditionalOnClass
で、クラスパスにorg.apache.catalina.Cluster
クラスが存在する場合に自動設定定義が有効化されるようになっています。
Spring Bootでは、著名な様々なソフトウェアの自動設定を行なうAutoConfigureクラスが提供されています。以下は、spring-bootのautoconfigureプロジェクトのリポジトリですが、cassandraやmongo、solrなどのAutoConfigurationクラスが用意されているのが分かります。
AutoConfigure機能は、spring-boot-autoconfigure
というプロジェクトで定義されており、spring-boot-starter
プロジェクトをライブラリとして追加すると、依存ライブラリとして追加されます。
さて、Spring BootでWebアプリケーション開発を行なうためのstarterライブラリとして、spring-boot-starter-web
があります。starter-webの依存ライブラリには、spring-web
、spring-webmvc
があり、Spring MVCを使ったWebアプリケーション開発のベースが整います。
以下は、Spring Bootのバージョン2.0.4.RELEASE
で、spring-boot-starter-web
を依存関係のcompileに指定した場合の依存関係グラフです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
compile - Dependencies for source set 'main' (deprecated, use 'implementation ' instead). \--- org.springframework.boot:spring-boot-starter-web -> 2.0.4.RELEASE +--- org.springframework.boot:spring-boot-starter:2.0.4.RELEASE | +--- org.springframework.boot:spring-boot:2.0.4.RELEASE | | +--- org.springframework:spring-core:5.0.8.RELEASE | | | \--- org.springframework:spring-jcl:5.0.8.RELEASE | | \--- org.springframework:spring-context:5.0.8.RELEASE | | +--- org.springframework:spring-aop:5.0.8.RELEASE | | | +--- org.springframework:spring-beans:5.0.8.RELEASE | | | | \--- org.springframework:spring-core:5.0.8.RELEASE (*) | | | \--- org.springframework:spring-core:5.0.8.RELEASE (*) | | +--- org.springframework:spring-beans:5.0.8.RELEASE (*) | | +--- org.springframework:spring-core:5.0.8.RELEASE (*) | | \--- org.springframework:spring-expression:5.0.8.RELEASE | | \--- org.springframework:spring-core:5.0.8.RELEASE (*) | +--- org.springframework.boot:spring-boot-autoconfigure:2.0.4.RELEASE | | \--- org.springframework.boot:spring-boot:2.0.4.RELEASE (*) | +--- org.springframework.boot:spring-boot-starter-logging:2.0.4.RELEASE | | +--- ch.qos.logback:logback-classic:1.2.3 | | | +--- ch.qos.logback:logback-core:1.2.3 | | | \--- org.slf4j:slf4j-api:1.7.25 | | +--- org.apache.logging.log4j:log4j-to-slf4j:2.10.0 | | | +--- org.slf4j:slf4j-api:1.7.25 | | | \--- org.apache.logging.log4j:log4j-api:2.10.0 | | \--- org.slf4j:jul-to-slf4j:1.7.25 | | \--- org.slf4j:slf4j-api:1.7.25 | +--- javax.annotation:javax.annotation-api:1.3.2 | +--- org.springframework:spring-core:5.0.8.RELEASE (*) | \--- org.yaml:snakeyaml:1.19 +--- org.springframework.boot:spring-boot-starter-json:2.0.4.RELEASE | +--- org.springframework.boot:spring-boot-starter:2.0.4.RELEASE (*) | +--- org.springframework:spring-web:5.0.8.RELEASE | | +--- org.springframework:spring-beans:5.0.8.RELEASE (*) | | \--- org.springframework:spring-core:5.0.8.RELEASE (*) | +--- com.fasterxml.jackson.core:jackson-databind:2.9.6 | | +--- com.fasterxml.jackson.core:jackson-annotations:2.9.0 | | \--- com.fasterxml.jackson.core:jackson-core:2.9.6 | +--- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.9.6 | | +--- com.fasterxml.jackson.core:jackson-core:2.9.6 | | \--- com.fasterxml.jackson.core:jackson-databind:2.9.6 (*) | +--- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.6 | | +--- com.fasterxml.jackson.core:jackson-annotations:2.9.0 | | +--- com.fasterxml.jackson.core:jackson-core:2.9.6 | | \--- com.fasterxml.jackson.core:jackson-databind:2.9.6 (*) | \--- com.fasterxml.jackson.module:jackson-module-parameter-names:2.9.6 | +--- com.fasterxml.jackson.core:jackson-core:2.9.6 | \--- com.fasterxml.jackson.core:jackson-databind:2.9.6 (*) +--- org.springframework.boot:spring-boot-starter-tomcat:2.0.4.RELEASE | +--- javax.annotation:javax.annotation-api:1.3.2 | +--- org.apache.tomcat.embed:tomcat-embed-core:8.5.32 | +--- org.apache.tomcat.embed:tomcat-embed-el:8.5.32 | \--- org.apache.tomcat.embed:tomcat-embed-websocket:8.5.32 | \--- org.apache.tomcat.embed:tomcat-embed-core:8.5.32 +--- org.hibernate.validator:hibernate-validator:6.0.11.Final | +--- javax.validation:validation-api:2.0.1.Final | +--- org.jboss.logging:jboss-logging:3.3.2.Final | \--- com.fasterxml:classmate:1.3.4 +--- org.springframework:spring-web:5.0.8.RELEASE (*) \--- org.springframework:spring-webmvc:5.0.8.RELEASE +--- org.springframework:spring-aop:5.0.8.RELEASE (*) +--- org.springframework:spring-beans:5.0.8.RELEASE (*) +--- org.springframework:spring-context:5.0.8.RELEASE (*) +--- org.springframework:spring-core:5.0.8.RELEASE (*) +--- org.springframework:spring-expression:5.0.8.RELEASE (*) \--- org.springframework:spring-web:5.0.8.RELEASE (*) |
spring-web
、spring-webmvc
、そしてspring-boot-autoconfigure
も依存ライブラリとしてクラスパスに追加されます。そして、webmvcで必要となるコンフィグレーションもautoconfigureライブラリに内包されており、すぐにSpring MVCでWebアプリケーション開発が行えるようになっているようです。
Spring BootでMVCのWebアプリケーション開発をするための下地は、STS(Spring Tool Suite)を使ってプロジェクト「Spring Boot>Spring Starter Project」作成をすると、すぐに構築できます。
組み込みたい依存ライブラリを選択します。
また、同様な事は、以下のウェブページからも可能です。
@EnableWebMvc
SpringでのWebMvcコンフィグレーション
Springでは、アノテーションorg.springframework.web.servlet.config.annotation.EnableWebMvc
をクラス定義に付与する事で、Spring MVCが提供してくれているコンフィグレーションクラスがインポートされ、必要となるコンポーネントのBean定義が自動で行われるようになっています。
1 2 3 4 5 6 |
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Import(DelegatingWebMvcConfiguration.class) public @interface EnableWebMvc { } |
EnableWebMvcの定義を見ると、アノテーション@Import
で、org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration
クラスがインポートされるようになっています。このクラスは、基本的なコンフィグレーションを担うWebMvcConfigurationSupportクラスを継承しています。また、WebMvcConfigurerCompositeクラスをメンバ変数に持ち、WebMvcConfigurerオブジェクトらにコンフィグレーションを委譲するようになっています。WebMvcConfigurerオブジェクトは、@Autowired
でインジェクトされるようになっています。
以下、各クラスの実装の抜粋です。(Branch 5.0.x)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@Configuration public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport { private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite(); @Autowired(required = false) public void setConfigurers(List<WebMvcConfigurer> configurers) { if (!CollectionUtils.isEmpty(configurers)) { this.configurers.addWebMvcConfigurers(configurers); } } ... } |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class WebMvcConfigurerComposite implements WebMvcConfigurer { private final List<WebMvcConfigurer> delegates = new ArrayList<>(); public void addWebMvcConfigurers(List<WebMvcConfigurer> configurers) { if (!CollectionUtils.isEmpty(configurers)) { this.delegates.addAll(configurers); } } ... } |
従って、アノテーション@EnableWebMvc
が@Configuration
クラスのいずれか1つ(@Configuration
が付与されるクラスは複数存在し得るため)に付与されており、クラスパス上に@Configuration
を付与したWebMvcConfigurerインターフェース実装のクラスを設置する事で、コンフィグレーションのカスタマイズができるようになっているようです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package com.example.demo; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @EnableWebMvc @Configuration public class MyWebConfig implements WebMvcConfigurer { @Override public void configurePathMatch(PathMatchConfigurer configurer) { // Do something System.out.println(configurer); } ... } |
最新のSpring(5.0)より前のバージョンでは、WebMvcConfigurerAdapterクラスを継承していたようですが、5.0以降ではInterfaceのdefault実装を使用しているため、直接WebMvcConfigurerインターフェースを実装したクラスを定義できるようになっています。
Spring BootのWebMvcコンフィグレーション
Spring Bootのautoconfigureライブラリでは、
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
が、@EnableWebMvc
相当の処理を担当しているようです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
@Configuration @ConditionalOnWebApplication(type = Type.SERVLET) @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class }) @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10) @AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class }) public class WebMvcAutoConfiguration { ... @Configuration @Import(EnableWebMvcConfiguration.class) @EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class }) @Order(0) public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ResourceLoaderAware { ... } /** * Configuration equivalent to {@code @EnableWebMvc}. */ @Configuration public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration { ... } ... } |
WebMvcAutoConfigurationAdapterクラスで、EnableWebMvcConfigurationクラスがインポートされ、EnableWebMvcConfigurationクラスは内部クラスとして定義されています。そして、EnableWebMvcConfigurationクラスはDelegatingWebMvcConfigurationクラスを継承しているため、DelegatingWebMvcConfigurationクラスのように振る舞います。
このことから、Spring Bootでは@EnableWebMvc
を明示的に指定しなくとも、@Configuration
を付与したWebMvcConfigurerインターフェースを実装したクラスをコンフィグレーションクラスとしてクラスパス上に配置していれば良いようです。WebMvcConfigurationSupportクラスを継承したクラスでコンフィグレーションを記述した場合は、EnableWebMvcConfigurationクラスはインポートされません。SpringのDocsにもあるように、WebMvcConfigurerインターフェースによるカスタマイズを使用しない場合は、WebMvcConfigurationSupportクラスかDelegatingWebMvcConfigurationクラスを直接継承し、コンフィグレーションを記述することになるようです。
If WebMvcConfigurer does not expose some more advanced setting that needs to be configured consider removing the @EnableWebMvc annotation and extending directly from WebMvcConfigurationSupport or DelegatingWebMvcConfiguration, e.g.:
123456789101112131415 @Configuration@ComponentScan(basePackageClasses = { MyConfiguration.class })public class MyConfiguration extends WebMvcConfigurationSupport {@Overridepublic void addFormatters(FormatterRegistry formatterRegistry) {formatterRegistry.addConverter(new MyConverter());}@Beanpublic RequestMappingHandlerAdapter requestMappingHandlerAdapter() {// Create or delegate to "super" to create and// customize properties of RequestMappingHandlerAdapter}}
コンフィグレーションをカスタマイズしたい場合、通常はWebMvcConfigurerインターフェースを実装したコンフィグレーションクラスを定義すればよいと思います。デフォルトで、すぐにアプリケーション開発ができるような設定がなされた状態となっているからです。
参考リンク
- https://www.logicbig.com/how-to/code-snippets/jcode-spring-mvc-webmvcconfigurer.html
- https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-web-applications.html#boot-features-spring-mvc-auto-configuration
- https://www.ibm.com/developerworks/jp/java/library/j-spring-boot-basics-perry/index.html
- https://www.logicbig.com/tutorials/spring-framework/spring-web-mvc/spring-enablewebmvc-annotation.html
参考書籍
翔泳社
売り上げランキング: 7,987
本書籍で一通り学習しましたが、ページ数が豊富で幅広くトピックが取り上げられているのでお勧めです。Java言語そのものの知識は必要なので、『パーフェクトJava』などで基礎は学習しておくと良いです。
技術評論社
売り上げランキング: 210,028
技術評論社
売り上げランキング: 147,078
コメント