스프링부트 원리

백기선님의 스프링부트 개념과 활용을 학습하며 정리한 내용입니다.

1. 의존성 관리 이해

1
2
3
4
5
<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.0.3.RELEASE</version>
</parent>

parent안에 영역내에 또 하나의 parent가 존재합니다.

1
2
3
4
5
6
<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-dependencies</artifactId>
  <version>2.0.3.RELEASE</version>
  <relativePath>../../spring-boot-dependencies</relativePath>
</parent>

위의 parent영역에 스프링프레임워크 의존성에 관한 버전이나 사용을 관리합니다. 이러한 영역을 구분하여 의존성관리를 되면 개발에 더욱 집중할 수 있도록 시간과 비용을 줄여줍니다.

2. 의존성 관리 응용

참고 사이트

https://mvnrepository.com/

2-1. 스프링부트가 버전관리 해주는 경우 의존성 추가

스프링부트가 지원해주지 않는 의존성은 아래와 같이 버전을 표시해줍니다.

스크린샷 2019-07-22 오후 11 27 59


2-2. 스프링부트가 버전관리를 해주지 않는 경우 의존성 추가

pom.xml에 다음과 같은 properties를 선언합니다.

1
2
3
4
//변경하고자 하는 버전 명시
<properties>
	<spring.version>5.0.8.RELEASE</spring.version>
</properties>


3. 자동 설정 이해

톰캣이 다른 설정 없이 구동할 수 있는 이유중 하나는 @SpringBootApplication 안에 있는 @EnableAutoConfiguration 때문입니다. 이러한 역할을 하는 다른 어노테이션으로 @SpringBootConfiguration@ComponentScan 가 있습니다. 스프링부트는 빈이 두 단계로 나뉘어 등록이 되는데 첫번째로는 @ComponentScan 두번째는 @EnableAutoConfiguration 가 동작하게 됩니다.

3-1. @Configuration

스크린샷 2019-07-23 오후 11 35 59

해당 파일 목록의 key값의 하위 configuration 파일들은 모두 기본 설정(autoConfiguration)을 말합니다.


3-2. ConditionalOn XxxYyyZzz

조건에 따라 해당 설정파일들을 사용할지 안할지 지정할 수 있는 어노테이션을 말합니다. 결국 사용자가 직접 커스터마이징을 하여 설정파일들을 관리하여 사용할 수 있는 것을 뜻합니다.

ex

1
2
//서블릿과 디스패쳐서블릿이 클래스패스에 존재할 때 사용 access 
@ConditionalOnClass({Sevlet.class, DispatcherServlet.class })
  1. 모든 jar파일중 spring.factories에 등록된 EnableAutoConfiguration 키값의 모든 클래스를 확인
  2. 컨디션의 조건에 맞으면 빈에 등록

4. 자동설정 만들기 1

4-1. starter와 AutoConfigure

  • 의존성 추가
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<dependencies>
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-autoconfigure</artifactId>
  </dependency>
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-autoconfigure-processor</artifactId>
      <optional>true</optional>
  </dependency>
</dependencies>

<dependencyManagement>
  <dependencies>
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-dependencies</artifactId>
          <version>2.0.3.RELEASE</version>
          <type>pom</type>
          <scope>import</scope>
      </dependency>
  </dependencies>
</dependencyManagement>
  • SolomanConfiguration.class @Configuration
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
@Configuration
public class SolomanConfiguration {

  @Bean
  public Soloman Soloman() {
    Soloman soloman = new Soloman();
    soloman.setName("Leej");
    soloman.setHowlong(9);
    return soloman;
  }
}
  • src/main/resourse/META-INF에 spring.factories 파일 추가

  • spring.fatories에 설정파일 추가

    1
    2
    
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    com.easyh.SolomanConfiguration
  • mvn install

    • 프로젝트 빌드 후 jar파일 생성
  • 프로젝트에서 pom.xml 에 디펜던시 추가

1
2
3
4
5
<dependency>
  <groupId>com.easyh</groupId>
  <artifactId>easyh-springboot-starter</artifactId>
  <version>1.0-SNAPSHOT</version>
</dependency>
  • 프로젝트 빌드 후 의존성이 주입된 것을 확인

스크린샷 2019-07-24 오전 12 05 28

  • ApplicationRunner 클래스 작성
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
@Component
public class SolomanRunner implements ApplicationRunner {
    //의존성 주입 
    @Autowired
    Soloman soloman;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println(soloman);
    }
}
  • 결과

스크린샷 2019-07-24 오전 12 49 03

5. Properties 파일을 통한 의존성 주입

의존성을 사용하고자 하는 프로젝트에 resourse/application.properties 파일 생성합니다.

해당 파일에 다음과 같이 내용을 입력합니다.

1
2
soloman.name = study Springboot
soloman.how-long = 100

의존성을 주입해줄 프로젝트에 사용할 객체 SolomanProperties라는 이름의 클래스를 생성합니다.

 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
package com.easyh;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("soloman")
public class SolomanProperties {

    private String name;
    private int howlong;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getHowlong() {
        return howlong;
    }

    public void setHowlong(int howlong) {
        this.howlong = howlong;
    }

}

@ConfigurationProperties("soloman") 어노테이션의 인자는 사용할 prefix를 입력해줍니다. 이후 미리 만들어놓은 SolomanConfiguration에 다음과 같이 작성합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
@Configuration
// properties 파일을 통해 등록하기 의존성 주입하기
@EnableConfigurationProperties(SolomanProperties.class)
public class SolomanConfiguration {

    @Bean
    //빈이 없으면 이 빈을 등록하기
    @ConditionalOnMissingBean
    public Soloman Soloman(SolomanProperties prop) {
        Soloman soloman1 = new Soloman();
        soloman1.setName(prop.getName());
        soloman1.setHowlong(prop.getHowlong());
        return soloman1;
    }
}

properties 파일을 통해 의존성을 주입받기 위해 @EnableConfigurationProperties 어노테이션을 선언해주며 사용할 클래스 SolomanProperties를 넣어줍니다. 이후 Soloman의 값을 리턴해주는 메소드에 선언한 Properties를 인자로 넘겨줌으로써 프로퍼티 파일에서 선언한 값을 리턴해주게 됩니다.

6. 스프링부트의 내장 웹서버 이해

스프링부트는 서버가 아니고 내장 서블릿 컨테이너를 쉽게 사용할 수 있게 해주는 툴입니다. 서버는 톰캣, 네티, 언더토우, 엔진엑스등이 해당합니다.


6-1. 스프링부트의 자동설정 역할

ServletWebServerFactoryAutoConfiguration = 서블릿 웹 서버 생성

DispatcherServletAutoConfiguration = 서블릿 생성 후 등록

  • 톰캣 객체 생성
  • 포트 설정
  • 톰캣 컨텍스트 추가
  • 서블릿 생성
  • 톰캣에 서블릿 추가
  • 컨텍스트 서블릿 매핑
  • 톰캣 실행

Lib -> autoconfigure -> spring-boot-autoconfigure-2.0.3 -> META-INF -> spring.factories -> ServletWebServerFactoryAutoConfiguration

ServletWebServerFactoryAutoConfiguration 클래스내에 내장 웹서버에 대한 정보와 기능을 담고 있습니다.

7. 내장 웹서버 응용

스프링부트의 프로젝트의 기본 서버는 톰캣입니다. 이를 변경하는 방법에 대해 알아보겠습니다. 프로젝트의 pom.xml 파일을 다음과 같이 기본 톰캣을 exclusion 해줍니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
  <exclusions>
    <!-- 톰캣 제거 -->
    <exclusion>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
    </exclusion>
  </exclusions>
</dependency>

<!-- 사용할 다른 서버 -->
 <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>

이후 application.properties 파일에 server.port=사용할port번호 를 부여하고 애플리케이션을 실행하면 다음과 같은 메세지를 확인할 수 있습니다.

Undertow started on port(s) 9080 (http) with context path

추가적으로 application.properties 파일에 spring.main.web-application-type=none를 선언한다면 이는 웹서버가 실행되는게 아니라 일반적인 애플리케이션으로 실행되게 됩니다. 또한 랜덤한 port를 부여하고 싶다면 port = 0 을 주면 가능합니다.


8. 내장웹서버 활용 2

application.properties 파일에 ssl에 관한 설정을 선언합니다.

1
2
3
4
server.ssl.key-store=keystore.p12
server.ssl.key-store-password=userPassword
server.ssl.key-store-type=PKCS12
server.ssl.key-alias=spring

이후 터미널을 실행시킨 후 아래와 같은 명령어를 입력 후 keystore를 생성합니다.

keytool -genkey -alias spring -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 4000

스크린샷 2019-08-09 오전 12 05 42

화면에 https로 접속을 해보면 다음과 같은 웹페이지가 보여지게 됩니다.

이후 간단한 @GetMapping("/hello") 어노테이션을 가진 메소드를 생성하고 터미널에서 curl -I -k –http2 http://localhost:8080/hello 를 입력하면 200 OK가 뜨는 것을 확인할 수 있습니다.

스크린샷 2019-08-11 오후 11 27 54


8-1. HTTP/2 Configure

application.properties파일에 server.http2.enabled=true 추가

위에 옵션을 톰캣 서버를 사용하고자 할때는 **Tomcat 9 and JDK 9 **이상일때만 사용하는게 편합니다. 이하 버전에서는 디렉토리와 추가 설정등이 필요하기 때문에 일을 만드는 작업을 하게 되어 추천하지 않습니다.

9. 독립적 실행 JAR

  • mvn package 명령어를 사용해 jar 파일 생성
    • spring-maven-plugin 기능 (패키징)
  • target 디렉토리로 이동하여 java -jar jar파일명 서버 실행 (애플리케이션 구동)
  • jar 파일 하나에 애플리케이션에 필요한 모든 것들로 구성
    • org.spring.framework.boot.loader.jar.JarFile 사용하여 내장 jar파일 읽기

스크린샷 2019-08-11 오후 11 28 03

MANIFEST.MF 파일은 jar 파일을 실행할 수 있는 다양한 환경 구성을 정의하는 기능을 합니다.

Reference