✔ 발단
사내에서 프로젝트가 끝나고, 빈 시간이 남음에 따라 기존 Spring Framework로 구현된 레거시 프로젝트를 Spring Boot로 전환하는 작업을 시작하게 되었다. 전환하게 된 사유는 다음과 같다.
- 로컬 구동시간, 빌드 시간이 너무 길었다.. + 셋팅이 번거로웠음
- 로컬에서 프로젝트를 구동하는데 걸리는 시간은 7~8분 가량이였고, '이거.. .맞는건가?' 라는 생각이 들어 이전 직장에서 레거시 프로젝트를 전환해본 것을 경험삼아 리팩토링을 시작하게 되었다..
- 빌드 시간 역시.. 5분은 거뜬하게 넘었고
- Apache Tomcat 서버를 사용하고, 개발 환경에 DB DNS세팅까지 해야하는 번거로움이 존재했다.
- 입사하자마자 내가 담당하게 된 서비스임에도 어떻게 구성되어있는지 제대로 이해하지 못한 상태였다.
- 백엔드 개발자를 시작하고, 나는 현업에서 스프링 레거시 서비스를 담당해 본 경험이 없었다. (실무에서 framework -> boot로의 전환 경험은 있었지만 꽤나 소규모의 프로젝트였어서 수월하게 진행됐었다..) 신규 프로젝트 위주로 맡게되어 부트로 커리어를 시작했고, 스프링 기본구성에 대한 이해가 깊지 않았다. 하지만 이번 직장에서 레거시 서비스를 담당하게 됨에 따라 이에 대한 기본 이해가 필요했다.
- 배포의 번거로움
- 사실 최종 목표는 '무중단 배포' 구현이였다. 현재 AWS서버에 server 1, server 2로 올라가 있는 상태였는데 배포를 한 번 하려면 Git Push -> 젠킨스 배포 -> 로드밸런서 server 2 해제, server 1 배포 -> 로드밸런서 server 1 해제, server 2 배포 의 흡사 청기올려 백기올려와 같은 과정을 거쳐야했다...
- 매번 요청이 있을 때마다 의도치 않게 청기백기게임을 하면서, 전 직장에서 사용했던 Blue-Green 전략으로 무중단 배포를 구현할 수 있을 것 같다는 생각이 문득 들었다. 이때 단순히 했던 생각은 Boot로 전환해 빌드 시간을 줄이고, 무중단 배포까지 구현해보자! 였다....
- 그냥... 부트 쓰고싶었다
- 개발자라면 신기술(Spring Boot는 신기술이라고 하기도 뭐하지만..)에 열려있는 자세가 기본 소양이라고 생각한다. 그래도 꾸준히 업데이트 되고 있고, 자바 개발자들이 사랑하는 프레임워크인 스프링 부트를 사용하고 싶었다.
✔ 가장 먼저 한 일은...
역시 나의 분신 GPT에게 물어보는 것이였다..
음..그렇군..
처음으로 한 일은.. maven을 사용하고 있는 Spring 프로젝트의 pom.xml에 Srping boot를 추가하는 것이였다..
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.X.X.RELEASE</version> <!-- Spring Boot의 버전 -->
<relativePath/> <!-- lookup parent from repository -->
</parent>
- parent 섹션은 Spring Boot에서 공통된 Maven 설정 및 의존성 관리를 활용할 수 있도록 해준다.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
- spring boot starter web을 의존성에 추가한다.
- spring-boot-starter-web은 Spring Boot로 웹 애플리케이션을 개발할 때 필요한 핵심 라이브러리와 설정을 포함하고있는데
- Spring MVC, 내장 톰캣, Restful 개발도구 등 기존 Spring framework 에서 의존성을 하나~하나 추가해줘야 했던 것들을 모아둔 것으로 볼 수 있다.
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
- Spring Boot 애플리케이션을 빌드하기 위한 Maven 플러그인 설정을 정의한다.
일단 이것들만 추가해줘도 스프링 부트는 어떻게 깔린다..
다음으로 한 일은 Spring boot starter 하위에 있는 의존성과 중복되는 애들을 제거해주는 것이였다.
- spring-context
- Spring Framework의 핵심 모듈로, 애플리케이션 컨텍스트와 빈 관리를 지원한다.
- spring-webmvc
- Spring MVC 프레임워크를 구현한 모듈로, 웹 애플리케이션의 MVC 아키텍처를 구현하고 웹 요청을 처리하는 데 사용된다.
- spring-tx
- Spring의 트랜잭션 관리를 지원하는 모듈이다.
- spring-orm
- Spring Framework와 JPA(Hibernate) 간의 통합을 제공한다.
- tomcat-dbcp
- Tomcat에서 제공하는 데이터베이스 커넥션 풀 라이브러리로, 데이터베이스 연결을 관리하고 효율적으로 사용할 수 있게 해준다.
- 보통 Spring에서는 데이터베이스 커넥션 풀 라이브러리로는 HikariCP를 사용하는데 이 프로젝트에서는 tomcat-dbcp라는 라이브러리를 사용하고 있었어서.. 새로웠다..
- javax.servlet-api
- javax.servlet.jsp
이것들은 Spring boot starter web에 종속되어 있는 의존성들이라...
과감히 다 지웠다....
✔ @SpringBootApplication 클래스 생성하기
Spring Boot에 대한 의존성을 추가했으면 다음으로 할 일은 @SpringBootApplication 어노테이션을 사용하는 메인 클래스를 만들 차례이다. 보통 Spring IDE나 start.spring.io를 통해 Spring Boot를 시작하면 자동으로 만들어주는 {project-name}Application.java 클래스를 직접 생성해야 하는데, @SpringBootApplication 어노테이션이 어떤 역할을 하는지부터 알아보자.
- @SpringBootApplication 어노테이션은 @Configuration, @EnableAutoConfiguration, @ComponetScan 어노테이션의 조합이다.
- @Configuration : Spring Bean 구성을 정의하는 Java 구성 클래스임을 나타내며, Spring 애플리케이션 컨텍스트에 Bean을 추가하는 데 사용된다.
- @EnableAutoConfiguration : Spring Boot의 자동 구성 기능을 활성화 한다. 이 어노테이션은 애플리케이션에 필요한 빈을 자동으로 구성하고 설정하는 데 사용되는데 (dispatcher-servlet.xml의 context:component-scan의 기능을 한다고 보면 된다) classpath 및 propertiy 설정을 기반으로 최상의 설정을 찾아 애플리케이션을 시작할 수 있도록 돕는다.
- @ComponentScan : Spring 컴포넌트 스캔을 활성화하고, 지정된 패키지와 하위 패키지에서 @Component, @Service, @Repository, @Controller 등의 스프링 애노테이션을 가진 클래스를 찾아 Spring Bean으로 등록하는 기능을 한다.
- 위의 세가지 어노테이션의 조합으로, 애플리케이션의 최상단 패키지에 메인 클래스를 생성해 @SpringBootApplication 어노테이션을 추가하면 본격적으로 Spring Boot 프로젝트를 시작하는 데 필요한 모든 구성을 자동으로 처리해준다.
✔ Bean 등록하기
이렇게 1차적으로 Spring Boot를 프로젝트에 추가했고 Boot가 설치됨으로서 불필요해진 의존성들은 전부 소거했다. 하지만 boot가 추가됐다고 해서.. 당연히 모든게 적용되는건 아니다. Spring Framework에서 xml으로 구성된 여러 설정파일들을 Boot로 옮겨주는 작업이 필요한데, 특히 Spring Framework는 Bean을 xml으로 등록하는 경우가 다수이므로 이에 대한 핸들링이 필요하다. webapp 패키지의 WEB-INF/spring 경로에 있는 dispatcher-servlet.xml 을 포함한 xml파일들을 분석해보자
현업에서 사용 되고 있는 코드다보니 직접 첨부는 못하지만, dispatcher-servlet.xml 에 설정되어있는 요소들은 다음과 같았다.
<context:component-scan base-package="" />
- Spring Boot의
@SpringBootApplication
어노테이션이 포함하고있는@ComponentScan
어노테이션이 기본 패키지를 스캔하도록 설정 되어 있다. - Spring Boot는 자동으로 해당 패키지와 하위 패키지에서 @Component 어노테이션이 지정된 클래스를 검색해서 빈으로 등록한다.
- 따라서
@SpringBootApplication
어노테이션이 붙은 메인 클래스를 생성해놓은 상태라면, 따로 설정해야 할 부분은 없다.
- Spring Boot의
<context:annotation-config />
- Spring Framework 2.5 버전 이후에 사용되는 방식이라고 하는데... Spring의
@Autowired
,@Required
,@PostConstruct
와 같은 애노테이션을 활성화 하는 기능을 한다. - 역시
@SpringBootApplication
에서 자동 구성 기능을 제공하고 있기 때문에@Autowired
와 같은 스프링 애노테이션들은 자동으로 활성화된다.
- Spring Framework 2.5 버전 이후에 사용되는 방식이라고 하는데... Spring의
jee:jndi-lookup
- Java EE 기반 애플리케이션에서 JNDI (Java Naming and Directory Interface) 리소스를 검색하는 데 사용되는 스프링 프레임워크의 XML 구성 요소라고 하는데...많이 생소하게 느껴졌다
- DB 커넥션 풀과 같은 정보를 중앙관리 하는 데 사용된다고 한다...
- 즉 고유 이름을 부여하여 리소스를 중앙 관리하고, 리소스에 접근하기 위한 표준 Java API라고 하는데
- 굳이 이 JNDI라는 API를 사용해야 하나..? 라는 생각이 들었다
- 일단 현 프로젝트 구성상, 단일 어플리케이션으로 되어있으므로 커넥션들에 대해 중앙 관리가 필요하지 않았고
- 커넥션 풀에 고유 이름을 부여해서 얻는 장점...? 마땅히 필요하다고 느껴지지 않았다.
- 굳이 이 이름을 사용하기 위해서 Spring Boot에서 Config 파일을 생성하는 과정이 다소 번거로울 것 같다는 생각이 들어
- 마이그레이션하는 Spring Boot 프로젝트에서 JNDI는 사용하지 않는 것으로..
org.springframework.orm.hibernate4.LocalSessionFactoryBean
- 하이버네이트 통합을 위한 빈으로 다음 포스트에서 기술하겠다...
tx:annotation-driven
- 트랜잭션 관리를 위한 설정 요소이다. 이 또한 다음 포스트에서 기술하겠다...2
org.springframework.orm.hibernate4.HibernateTransactionManager
- Hibernate 트랜잭션 관리를 위한 Bean으로 다음 포스트에서 기술하겠다...3
org.springframework.web.multipart.commons.CommonsMultipartResolver
- Spring Framework에서 multipart 파일 업로드를 처리하는 데 사용되는 빈으로, HTTP 요청으로부터 파일 업로드를 파싱하고 처리하는데 도움을 준다.
- Spring Boot에서는 별도의 빈 설정이 필요하지 않고, application.properites (application.yml) 파일에 설정을 추가하여 파일 업로드에 대한 설정을 제어할 수 있다.
spring: mvc: view: prefix: /WEB-INF/views/ suffix: jsp
org.springframework.web.servlet.view.InternalResourceViewResolver
- 뷰(View)를 해석하고 렌더링하는 데 사용되는 뷰 리졸버 빈 객체이다.
- InternalResourceViewResolver 클래스는 뷰 이름을 해석하고, 뷰 인스턴스를 생성하고, 뷰를 렌더링하는 역할을 한다.
- Spring Boot에서는 역시 별도의 빈 설정이 필요하지 않고, application.properties (application.yml) 파일에 설정을 추가하여 뷰 리졸버 설정을 사용할 수 있다. 예시는 다음과 같다.
spring: mvc: view: prefix: /WEB-INF/views/ suffix: jsp
mvc:resources
- 정적 리소스(CSS, JS, 이미지 파일 등..)를 브라우저로 전달하기 위한 설정을 정의하는 데 사용된다.
- Spring Boot에서는 별도의 XML 설정 없이
src/main/resources/static/
디렉토리에 정적 리소스를 배치하는 것이 일반적이다. - 경로에 대한 정의가 추가적으로 필요한 경우에는, 다음과 같이 Config 클래스를 정의할 수 있다.
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/css/**/") .addResourceLocations("classpath:/static/css/"); } }
mvc:interceptors
- 인터셉터를 설정하기 위해 사용된다. 인터셉터를 사용하면 요청의 전처리 및 후처리 작업을 하거나, 특정 조건에 따라 요청을 중단하거나 리다이렉트할 수 있다.
org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
'업무..하면서' 카테고리의 다른 글
요즘 일하면서 느끼는 거 (0) | 2024.07.29 |
---|---|
다중 로그인 제어 적용하기 (0) | 2024.06.29 |
spring event로 이벤트 아키텍처 적용하기 (0) | 2024.02.02 |
클린 아키텍처 적용하기 (0) | 2024.01.16 |
Spring 로그 관리하기 (0) | 2023.12.12 |
댓글