이번 챕터에서는 SpringBoot에 대해서 알아보는 시간을 가져보도록 한다.
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>6.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.3</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
다음 경우와 같이 수 많은 친구들의 의존성을 관리 해줘야 한다.
예를 들면
- REST API - Spring framework, Spring MVC framework, JSON binding framework, ..
- Unit Tests - Spring Test, Mockito, JUnit, ...
이 친구들에 대한 버전과 의존성들을 일일히 관리해주는 것이 상당히 고된 일이다.
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/todo-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
사실 이후에 나올 것이긴 하지만 우리가 알고 있는 Spring의 DispatcherServlet
과 같은 설정도 Spring MVC 를 사용하기 위해서 직접 작성해야 했던 문제도 있었다.
<context:component-scan base-package=
"com.in28minutes" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/views/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
componentScan
을 당연시하게 사용한 것도 있었겠지만 사실 정의를 해줘야 하고 viewResolver
역시 정의를 하고 설정을 해줘야 한다!
사실 우리가 개발을 하면서 단순히 Spring 기술만을 사용하지는 않는다. 기능적인 요소는 아니지만 logging
,Error Handling
, Monitoring
과 같은 기능들은 어찌보면 필수로 가져가야 하는데 이것에 대한 설정도 해줘야 한다.
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<path>/</path>
<contextReloadable>true</contextReloadable>
</configuration>
</plugin>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
그렇지만 이제 Spring Boot에서 이런 문제를 해결하기 위해 다음과 같은 목표를 세웠다.
그래서 어떻게 이 목표들을 이룰 수 있었는지 한 번 알아보자.
우리가 흔히 알고 있는 Spring 을 시작할 때 보게 되는 start.spring.io
사이트를 통해 우리는 여러 초기 설정을 한 번에 하고 프로젝트를 시작할 수 있다.
또한 우리는 어떤 의존성들을 볼 때 spring-boot-starter- ~
과 같은 형태로 의존성들이 존재한다는 것을 알 수 있다.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
여기에 보이는 starter 내부를 들어가보면
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.1.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>6.1.1</version>
<scope>compile</scope>
</dependency>
우리가 초기에 설정해야 할 내용들에 대해서 시작할 때 반드시 필요한 의존성들을 그룹화하여 자동으로 의존성을 관리해주고 있다는 것을 알 수 있다.
이를 통해 프로젝트를 더 빨리 설정하고 시작할 수 있게 도와주는것이 spring boot의 spring-boot-starter라는 친구였다는 것을 알고 가자.
아까 이전에 말했던 것처럼 Spring으로만 진행을 하려고 했으면 여러가지 설정해줘야 하는 값들이 많다.
spirng mvc 를 사용해서 진행하려고 하는데 필요한 몇 가지 dependency jar가 존재하는데 수동으로 빈을 등록을 하지 않을 경우 자동으로 Spring Boot 에서 프로젝트로 하여금 설정을 하게 도와준다.
해당 기능은 devTools라고 했던 것처럼 개발을 하는데 편의를 주기위한 도구라고 생각을 했다.
예를 들어 이런 상황을 예로 들어보자.
개발을 하다가 오타가 나서 서버를 껐다가 다시 실행시켜야 하네... ㅠㅠㅠ
(수정 후, 서버 재시작)
또 오타가 있네
(수정 후, 서버 재시작)
반복~~
이러면 계속 서버를 껐다 켰다가 하는 설정들을 계속 해야하는데 이러면 너무 번거러운 작업들을 하지 않기로 했다.
그래서 Spring Boot DevTools
를 활용하여서 자동으로 재시작하고 실행할 수 있도록 도와주는 기능이 있다.
그리고 추가적으로 다음과 같은 기능들을 제공한다고 한다.
우선 강의에서는 Eclipse로 진행하셔서 그런지 몰라도 자동으로 알아서 바로 되었는데 Intellij에서는 몇 가지 설정이 필요했다.
해당 단계를 거치면 이제부터 코드를 다시 작성하고 저장을 할 때마다 서버가 재시작되어서 변경된 사항이 자동적으로 적용이 되는 것을 확인할 수 있다.
유의사항! 다른 코드들은 다 수정할 때 재시작이 되어지지만 pom.xml, build.gradle 과 같은 파일들은 수정하면 서버를 재시작해야 한다!
그래서 우리가 이전에 말했던 단점들에 대해서 일부 보완하여 Spring Boot에서 자동적으로 설정해준 부분들이 있었기 때문에 우리는 정말 쉽게 설정하고 의존성들을 관리하고 프로젝트를 실행할 수 있었다.
그래서 항상 프로젝트의 뒷편에서 이런 큰 일들을 Spring Boot가 해준다는 것에 감사하며 진행해야한다는 것을 느끼고 가야겠다.
사실 개발을 하다보면 개발자만 프로젝트 코드를 사용하는 것이 아니라 qa 팀, dev 팀, stage 팀, prod 팀 이렇게 보통 나눠서 확인을 한다고 하신다.
그렇기 때문에 개발자의 입장에서 사용하는 db, qa 팀 db 등등 여러가지 팀에서 사용하는 db도 달라야 했을 것이고 팀마다 환경이나 설정들이 달라야 할 필요가 있을 것이다.
그래서 Spring Boot를 통해서 사용할 수 있는 profile 기능을 활용하면 좋은 것이다.
Spring 에서 application-{환경이름}.properties
를 한 후
그리고 application.properties에 예시로 dev를 추가하게 되었을 때
spring.profiles.active=dev
application-dev.properties를 기준으로 동작을 하는것 같지만 실제로 application.properties + application-dev.properties 가 로딩이 되어진다. 이때 만약 중복되는 설정 값이 있다고 하면 application-dev.properties에 있는 값 기준으로 실행이 되어진다!
logging.level.org.springframework=debug
spring.devtools.restart.enabled=true
spring.profiles.active=dev
logging.level.org.springframework=trace
spring.devtools.restart.enabled=true
이렇게 진행이 되어졌을 때 logging.level 이 trace로 실행이 되어진다! 이런 것처럼 나중에 db 설정을 달리 해야하거나 해야할 때 잘 활용하면 좋은 기능이라고 생각한다.
다음 그림을 통해 OLD, 그리고 현재의 Embedded 한 접근 방법을 보게 되었을 때 단계별로 구분을 해봐도 옛날 방식이 더 많은 작업을 해야한다는 것을 알 수 있다.
spring-boot-starter-tomcat
, spring-boot-starter-jetty
, spring-boot-starter-undertow
Spring에 사실 모니터링 기능도 존재한다!
바로 Spring Boot Actuator
라고 부르는 기능인데 해당 기능을 사용하면 전반적인
액추에이터는 스프링 부트 애플리케이션의 모니터링이나 매트릭(metric)과 같은 기능을 HTTP와 JMX 엔드포인트를 통해 제공한다.
해당 기능을 사용하기 위해서는 아래와 같이 pom.xml에 의존성을 추가하고 실행하게 된다.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
그리고
application.properties 에
management.endpoints.web.exposure.include=*
이라고 하게 되었을 때 url 로 http://localhost:8080/actuator
로 접속하게 되었을 때
다음과 같이 여러가지 엔드포인트들에 대해서 제공을 해준다. 특히 이 중 health, metrics 부분을 확인하며 진행을 하는데 사실 다른 엔드 포인트들은 더 볼 필요가 없다면
management.endpoints.web.exposure.include=health,metrics
과 같이 설정하여
다음과 같이 확인할 수 있다. 실제로 들어가서 확인을 해보면 어플리케이션의 상태 체크나, 여러가지 통계 정보들에 대해서 json 파일의 형태로 보여진다는 것을 알 수 있다. 실제로 metrics 의 http.server.request
를 확인해보게되면 다음과 같이 보여지게 된다.
해당 정보들을 통해서 우리가 필요한 정보들을 spring-boot-actuator를 통해 모니터링 할 수 있다는 것도 알 수있는 시간이었다.