반응형

Spring Boot 란?

  • Spring 프로젝트가 제공하는 다양한 라이브러리와 프레임워크로 빨리게 사용할 수 있게 하는 프레임워크.
  • Dropwizard의 Spring 버전 같은 것.
  • 빌드하면 단일 jar 파일이 생긴다.
    • Web 어플리케이션의 경우, 내장 Tomcat을 시작 (Jetty와 Undertow로 전환 가능).
    • Web 응용 프로그램이 아니라 보통의 Java 프로그램으로도 동작하게 할 수 있다.
  • Maven이나 Gradle 같은 빌드 도구를 사용한다(Ant로는 가능하지 않다)
  • 사용하려는 컨포넌트를 종속적으로 추가하면 결합에 필요한 설정이 자동으로 이루어진다.


Hello World

Hello World 생성하기

Gradle 프로젝트를 생성한다.

디렉토리 spring-boot-hello-world를 생성하고, Gradle 프로젝트를 초기화한다.

$ mkdir spring-boot-hello-world
$ cd spring-boot-hello-world

Gradle 프로젝트를 초기화한다.

$ gradle init

BUILD SUCCESSFUL in 1s
2 actionable tasks: 2 executed

소스 코드 자바 디렉토리를 만든다.

$ mkdir -p src/main/java/sample/springboot

소스 코드를 작성한다.

build.gradle

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.6.RELEASE")
    }
}

apply plugin: 'java'
apply plugin: 'org.springframework.boot'

sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web")
}

jar.baseName = 'spring-boot-hello-world'

src/main/java/sample/springboot/Main.java

package sample.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class Main {

    public static void main(String[] args) {
        try (ConfigurableApplicationContext ctx = SpringApplication.run(Main.class, args)) {
            Main m = ctx.getBean(Main.class);
            m.hello();
        }
    }

    public void hello() {
        System.out.println("Hello Spring Boot!!");
    }
}

디렉토리 구조

$ tree
.
├── build.gradle
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
    └── main
        └── java
            └── sample
                └── springboot
                    └── Main.java

어플리케이션 실행

Gradle로 실행

$ gradle bootRun
 

> Task :bootRun

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.5.6.RELEASE)

(생략)
Hello Spring Boot!!
(생략)

BUILD SUCCESSFUL in 20s
3 actionable tasks: 3 executed

빌드 실행

$ gradle build
$ java -jar build/libs/spring-boot-hello-world.jar

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.5.6.RELEASE)

(생략)
Hello Spring Boot!!
(생략)

설명

build.gradle 설정

Spring Boot 용 Gradle 플러그인이 포함되어 있기 때문에 처음에 이를 로드한다.

build.gradle

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.6.RELEASE")
    }
}

apply plugin: 'org.springframework.boot'

그리고 일반적인 Java 프로그램을 만들 뿐이라면, spring-boot-starter에 종속(dependencies)되도록 추가한다.

build.gradle

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.springframework.boot:spring-boot-starter'
}

Spring Boot 기동

Spring Boot의 기동은 SpringApplication 클래스를 사용한다. 가장 간단한 방법은 SpringApplication#run (Object, String ...)을 사용하는 것이다.

Main.java

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class Main {

    public static void main(String[] args) {
        try (ConfigurableApplicationContext ctx = SpringApplication.run(Main.class, args)) {
            Main m = ctx.getBean(Main.class);
            m.hello();
        }
    }

    public void hello() {
        System.out.println("Hello Spring Boot!!");
    }
}
  • run () 메소드의 첫번째 인수는 @EnableAutoConfiguration으로 어노테이션 클래스의 Class 객체를 건네 준다.
    • Main 클래스는 @SpringBootApplication 어노테이션되어 있지만, 이것은 @Configuration, @EnableAutoConfiguration, @ComponentScan 3개의 클래스를 어노테이션 설정한 것과 동일하다.
    • @Configuration은 Spring의 다양한 설정을 Java 코드상에서 할 수 있도록 한 어노테이션이다.
      • 예전 Spring은 XML으로 설정을 썼지만, 지금은 Java 코드에서 설정하는 것이 주류를 이루고 있다 같다.
    • @EnableAutoConfiguration는 Spring 설정을 자동화하기 위한 어노테이션이다.
      • 이 종속성을 추가하는 것만으로 Spring MVC 등의 라이브러리를 설정 기입없이 사용할 수있게 된다.
    • @ComponentScan는 DI 컨테이너가 관리하는 Bean을 자동 등록하는 어노테이션이다.
      • 이제 주석 된 클래스를 기점으로 부하의 패키지를 재귀적으로 검색하여 @Component 어노테이션이 부여 된 클래스를 Bean으로 컨테이너에 등록한다.
    • 이 3 개의 어노테이션은 대체로 함께 사용하는 경우이 많기 때문에, @SpringBootApplication를 사용하면 조금 편해진다.
  • 두 번째 인수는 커멘드 라인의 인수를 전달한다.

Gradle에서 실행 빌드

어플리케이션의 기동은 spring-boot-gradle-plugin이 제공하는 bootRun 테스크를 사용한다.
jar 생성은, 보통의 build 테스크로 가능하다.
생성된 jar는 일반적으로 jar -jar <jar 파일>에서 실행할 수 있다.

소스 코드




Java 코드에서 Bean 정의

@Bean 어노테이션를 부여하여 Bean 생성하기

Hoge.java

package sample.springboot;

public class Hoge {

    private String name;

    public Hoge(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Hoge [name=" + name + "]";
    }
}

Main.java

package sample.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class Main {

    public static void main(String[] args) {
        try (ConfigurableApplicationContext ctx = SpringApplication.run(Main.class, args)) {
            Hoge h = ctx.getBean(Hoge.class);
            System.out.println(h);
        }
    }

    @Bean
    public Hoge getHoge() {
        System.out.println("Main#getHoge()");
        return new Hoge("hoge");
    }
}

실행 결과

Main#getHoge()
Hoge [name=hoge]

설명

  • @Bean 메소드를 어노테이션으로 설정하고 그 메소드를 통해 Bean의 인스턴스를 생성 할 수있게 된다.
  • 이런 방식의 Bean을 정의하는 방법은 @Configuration 어노테이션이 부여 된 클래스를 선언 할 수 있다.
    • @SpringBootApplication는 @Configuration 어노테이션이 부여 된 것과 같은 효과가 있다.

@Configuration 어노테이션이 부여 된 클래스를 별도로 생성하기

HogeProvider.java

package sample.springboot;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class HogeProvider {

    @Bean
    public Hoge getHoge() {
        System.out.println("HogeProvider#getHoge()");
        return new Hoge("hoge provider");
    }
}

Main.java

package sample.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class Main {

    public static void main(String[] args) {
        try (ConfigurableApplicationContext ctx = SpringApplication.run(Main.class, args)) {
            Hoge h = ctx.getBean(Hoge.class);
            System.out.println(h);
        }
    }
}

실행 결과

HogeProvider#getHoge()
Hoge [name=hoge provider]

설명

클래스에 @Configuration 어노테이션으로 부여하고 메소드에 @Bean 어노테이션으로 부여하면, 임의의 클래스 Bean을 생성하는 메소드를 정의할 수 있다.




Web 어플리케이션 기동

Hello World 수정하기

build.gradle

dependencies {
-   compile 'org.springframework.boot:spring-boot-starter'
+   compile 'org.springframework.boot:spring-boot-starter-web'
}

src/main/java/sample/springboot/Main.java

package sample.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Main {

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

src/main/java/sample/springboot/web/HelloController.java

package sample.springboot.web;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/hello")
public class HelloController {

    @RequestMapping(method=RequestMethod.GET)
    public String hello() {
        return "Hello Spring MVC";
    }
}

어플리케이션 실행

Gradle로 실행

$ gradle bootRun
(생략)
> :bootRun

curl으로 테스트하기

$ curl http://localhost:8080/hello
Hello Spring MVC

설명

Web 어플리케이션에 대한 의존성

build.gradle

dependencies {
-   compile 'org.springframework.boot:spring-boot-starter'
+   compile 'org.springframework.boot:spring-boot-starter-web'
}

Web 어플리케이션을 만드는 경우는 spring-boot-starter-web 모듈을 사용한다. 기본적으로 Spring MVC를 사용하여 Web 응용 프로그램을 만들게 된다.

기동 방법 변경

src/main/java/sample/springboot/Main.java

    public static void main(String[] args) {
-       try (ConfigurableApplicationContext ctx = SpringApplication.run(Main.class, args)) {
-           ....
-       }
+       SpringApplication.run(Main.class, args);

서버 시작 후 컨테이너가 종료 해 버리므로 try-with-resources 문장은 사용하지 않도록 변경한다.

Spring MVC 컨트롤러 클래스

src/main/java/sample/springboot/web/HelloController.java

@RestController
@RequestMapping("/hello")
public class HelloController {

    @RequestMapping(method=RequestMethod.GET)
    public String hello() {
        return "Hello Spring MVC";
    }
}

Web API의 진입 점(Entry point)이 되는 클래스를 만드는 경우 @RestController을 클래스에 부여한다.
Web API 대신 MVC에서 C가 되는 컨트롤러 원한다면 @Controller 어노테이션을 부여한다.
@RequestMapping에서 경로 및 HTTP 메소드의 매핑을 한다 (대략 JAX-RS와 같은 분위기).

소스 코드



서버 포트 번호 변경

서버 포트 번호 변경하기

application.properties

server.port=1598

어플리케이션 실행

$ gradle bootRun
(생략)
2017-08-17 22:30:13.211  INFO 14485 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 1598 (http)
(생략)

설명

  • server.port으로 포트 번호를 지정할 수 있다.
  • application.properties에 대한 설명은 여기.
  • 그 밖에도 다음과 같은 변경이 가능하다.
    • server.address : 서버 주소 (localhost로 하면 로컬에서만 액세스 할 수 없게 된다.)
    • server.sessionTimeout : 세션 타임아웃 시간.


응답과 요청 매핑

응답과 요청 매핑(Mapping Requests and Responses)

src/main/java/sample/springboot/web/Hoge.java

package sample.springboot.web;

public class Hoge {

    public int id;
    public String value;

    @Override
    public String toString() {
        return "Hoge [id=" + id + ", value=" + value + "]";
    }
}

src/main/java/sample/springboot/web/HelloController.java

package sample.springboot.web;

import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/hello")
public class HelloController {

    @RequestMapping(method=RequestMethod.POST)
    public Hoge hello(@RequestBody Hoge param) {
        System.out.println(param);

        Hoge hoge = new Hoge();
        hoge.id = 20;
        hoge.value = "Response";

        return hoge;
    }
}

어플리케이션 실행

curl으로 테스트하기

$ curl -H "Content-type: application/json" -X POST -d '{"id": 10, "value": "Request"}' http://localhost:8080/hello
{"id":20,"value":"Response"}

서버 콘솔 출력

Hoge [id=10, value=Request]

설명

  • 기본적으로 요청과 응답은 모두 JSON 의한 매핑이 되어 있다.
  • 매핑은 Jackson으로 하고 있고 있다 (그래서 매핑 조정은 Jackson 어노테이션으로 가능하다).



반응형

+ Recent posts