このガイドでは Spting Boot が迅速なアプリケーション開発にどのように役立つかをサンプルを提供します。 ちなみに http://start.spring.io/ で入力項目埋めるとプロジェクトの雛形がつくれます。
What you’ll build
これから Spring Boot で簡単なWebアプリケーションを構築して、いくつかの便利なサービスを追加していきます。
What you’ll need
How to complete this guide
以下から雛形をダウンロードできます。
git clone https://github.com/spring-guides/gs-spring-boot.git
が、ここではスクラッチで Gradle 使って進めることにします。
Build with Gradle
プロジェクト用のディレクトリを用意して、その中にソースディレクトリ作成します。
mkdir -p src/main/java/hello
build.gradle 作成していきます。
touch build.gradle
内容は以下。
buildscript { repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:1.1.10.RELEASE") } } apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'idea' apply plugin: 'spring-boot' jar { baseName = 'gs-spring-boot' version = '0.1.0' } repositories { mavenCentral() } dependencies { // tag::jetty[] compile("org.springframework.boot:spring-boot-starter-web") { exclude module: "spring-boot-starter-tomcat" } compile("org.springframework.boot:spring-boot-starter-jetty") // end::jetty[] // tag::actuator[] compile("org.springframework.boot:spring-boot-starter-actuator") // end::actuator[] testCompile("junit:junit") } task wrapper(type: Wrapper) { gradleVersion = '1.11' }
spring-boot-gradle-plugin が以下の面倒を見てくれます。
- 必要な jar あつめて fat-jar を作る
- main メソッド見つけてjar のマニフェストに自動的に書いて実行可能jarにする
- Spring Boot の依存を(書き換えることもできるけど)勝手に設定する
Learn what you can do with Spring Boot
Spring Boot はクラスパスと Beans の設定を見て必要な設定を自動的おこないます。
といっても、コード生成したり自動的に設定ファイル作るのではなくて、アプリケーションの起動時にコンテキストに応じて動的に設定を組み立てています。
Create a simple web application
作成するクラスのファイルを用意します。
touch src/main/java/hello/HelloController.java
touch src/main/java/hello/Application.java
HelloController.java はこんな感じになります。
package hello; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RequestMapping; @RestController public class HelloController { @RequestMapping("/") public String index() { return "Greetings from Spring Boot!"; } }
@RestController
は Spring MVC が web リクエストを扱うことを定義しています。
@RequestMapping
は / のリクエストがこのメソッドにマッピングされる定義です。
このメソッド呼ばれるとプレーンテキストを返しますが、これは @RestController
が @Controller
と @ResponseBody
を合わせた定義になってるためです。
では Application.java
package hello; import java.util.Arrays; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @EnableAutoConfiguration @ComponentScan public class Application { public static void main(String[] args) { ApplicationContext ctx = SpringApplication.run(Application.class, args); System.out.println("Let's inspect the beans provided by Spring Boot:"); String[] beanNames = ctx.getBeanDefinitionNames(); Arrays.sort(beanNames); for (String beanName : beanNames) { System.out.println(beanName); } } }
@Configuration
はアプリケーションコンテキストのソースファイルのしるし。
@EnableAutoConfiguration
は Spring Boot にクラスパスにあるBeanをよろしく設定してねというしるし。
@ComponentScan
で hello パッケージのコンポーネントやら設定やらサービスやらを自動で見つけてねというしるし。
SpringApplication.run()
でアプリケーションが launch されるけど、web.xml とかは全く不要です。
Run the application
起動してみます。最初だけ wrapper します。
gradle wrapper
あとはこれだけ。
./gradlew build && java -jar build/libs/gs-spring-boot-0.1.0.jar
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v1.1.10.RELEASE)
ロゴが出て起動します。
localhost:8080
でアクセスすると、Greetings from Spring Boot! が返れば成功です。
Add Unit Tests
次テスト。依存関係に以下を追加。
testCompile("org.springframework.boot:spring-boot-starter-test")
単体テストクラス作ります。
mkdir -p src/test/java/hello
touch src/test/java/hello/HelloControllerTest.java
テストコードは以下
package hello; import static org.hamcrest.Matchers.is; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.http.MediaType; import org.springframework.mock.web.MockServletContext; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders; @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = MockServletContext.class) @WebAppConfiguration public class HelloControllerTest { private MockMvc mvc; @Before public void setUp() throws Exception { mvc = MockMvcBuilders.standaloneSetup(new HelloController()).build(); } @Test public void getHello() throws Exception { mvc.perform(MockMvcRequestBuilders.get("/").accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(content().string(is("Greetings from Spring Boot!"))); } }
フルスタックのインテグレーションテストも簡単に書けます。
テストクラス用意して、
touch src/test/java/hello/HelloControllerIT.java
中身はこんな感じ
package hello; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; import java.net.URL; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.IntegrationTest; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.boot.test.TestRestTemplate; import org.springframework.http.ResponseEntity; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.web.client.RestTemplate; @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = Application.class) @WebAppConfiguration @IntegrationTest({"server.port=0"}) public class HelloControllerIT { @Value("${local.server.port}") private int port; private URL base; private RestTemplate template; @Before public void setUp() throws Exception { this.base = new URL("http://localhost:" + port + "/"); template = new TestRestTemplate(); } @Test public void getHello() throws Exception { ResponseEntity<String> response = template.getForEntity(base.toString(), String.class); assertThat(response.getBody(), is("Greetings from Spring Boot!")); } }
@IntegrationTest("${server.port=0}")
で組み込みのサーバがランダムなポート選ぶので、実際のポートは @Value("${local.server.port}")
で得られます。
以下でテスト実行。
./gradlew test
Add production-grade services
商用向けに actuator module 追加するので、以下の依存関係追加。
compile("org.springframework.boot:spring-boot-starter-actuator")
実行。
./gradlew build && java -jar build/libs/gs-spring-boot-0.1.0.jar
http://localhost:8080/health でアクセスするとヘルスチェック文字 {"status":"UP"} が得られます。あと、http://localhost:8080/env で環境変数取れたり、詳細は Spring Boot Reference Guide 参照。
商用向けなので、エンドポイントからの shutdown も出来なくなってます。
curl -X POST localhost:8080/shutdown
今回追加したのは spring-boot-starter-actuator
だけど、いろんな starter があります。
Spring Boot Reference Guide
らに詳しくは Spring Boot Reference Guide。