전환 사유

  • 대부분의 가이드, docs, 자료가 SpringBoot를 전제하고 있어 mvc 프로젝트 유지보수 시 불필요하게 리소스가 낭비되는 부분이 있음.
  • @MockBean, @SpyBean 등 SpringBoot의 TC 지원 애너테이션을 사용 할 수 없어 TC 작성 효율이 떨어지고 보일러플레이트 작성에 대한 진입장벽 높음.
  • SpringBoot로 전환하는게 장기적으로 유지보수비용이 더 세이브 될 것 같아 전환 결정.

 

As-is

  • spring-webmvc 4.3.4.RELEASE
  • 외장 tomcat
  • maven
  • jsp 코드 다수
  • 폴더 기반 deploy (war 사용하지 않고 디렉터리 전체를 배포)
    • 폴더 전체 배포는 아무래도 node_modules 같은 디렉터리는 디플로이 시 제외해야 하는 등 신경써야 하는 부분이 생겨서, 애플리케이션 구동 시 필요한 모든 정보를 war에 넣고 war만 배포하는게 유지보수 하기 더 편하다.

 

단계별로 전환하기

  • jsp 페이지가 많이 존재하는데, 스프링부트 내장 톰캣은 jsp를 빌트인으로 지원하지 않음.
  • jasper를 쓰면 내장 톰캣에서 jsp 쓸 수 있다지만, 이런 변수를 늘리면서 무리하게 executable jar 사용할 필요는 없어보임.
  • 또는 jsp 페이지를 모두 Thymeleaf 등으로 전환하는 방법도 있겠지만, 무리해서 일시에 전환하기 보다는 점진적으로 진행 할 수 있도록 전환 계획을 아래와 같이 수립.

---

  1. 의존성 spring mvc → springboot로 변경하고 설정 잡기 (외장 tomcat, jsp, 폴더기반 배포는 유지)
  2. jsp를 Thymeleaf 등으로 마이그 (시간 날 때 진행)
  3. 외장 tomcat 걷어내고 내장 tomcat 사용. jar 패키징 및 배포

 

의존성 spring mvc → springboot로 변경하고 설정 잡기

1-1. 의존성 세팅

<groupId>dev.umbum</groupId>
<artifactId>web</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>my-jsp-web</name>

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.9</version>
    <relativePath/>
</parent>
... 기존 의존성들 충돌 안나게끔 정리
  • 외장톰캣, war(폴더 기반 배포) 사용 할 것이기 때문에 embedded-tomcat, jasper 의존성 필요없음. 
  • 빌드 한 번 돌려본다. 

빌드 성공하면 다음으로

 

1-2. WebApplicationInitializer 전환

  • 기존 spring-webmvc 프로젝트에는 xml 기반 설정이라면 web.xml 설정파일이, java 기반 설정이라면 WebApplicationInitializer를 직접 구현한 구현체가 있을텐데 이를 마이그 해주어야 한다.
  • java 기반 설정 (WebApplicationInitializer) 되어 있는 경우 예시 (아래 코드)
public class WebApplicationInitializerImpl implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext container) throws ServletException {
        // servlet listener 등록
        // servlet filter 등록
        // property source 설정
        // spring.profiles.active 설정
        기타 다양한 설정
    }
}

 

  • spring-webmvc의 애플리케이션 진입점은 WebApplicationInitializer.onStartup 이므로, 이 부분을 제거해주고, SpringBoot의 애플리케이션 진입점인 @SpringBootApplication 를 설정해준다.
@SpringBootApplication(exclude = {
    DataSourceAutoConfiguration.class,
    DataSourceTransactionManagerAutoConfiguration.class,
    ... 기타 수동으로 설정하고 있기 때문에 AutoConfig 타면 안되는 항목들
})
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

 

 

  • 기존 구현체에서 수행하던 ServletFilter, ServletListener, PropertySource 등의 설정은 모두 삭제하고 아래와 같이 마이그해준다.
    • Filter와 Listener는 SpringBoot의 Bean 등록 방식으로 변경.
    • PropertySource 설정은 application.properties에서.
@Configuration
public class ServletConfig {

    @Bean
    public ServletListenerRegistrationBean<LogbackShutdownListener> logbackShutdownListener() {
        ServletListenerRegistrationBean<LogbackShutdownListener> registrationBean = new ServletListenerRegistrationBean<>();
        registrationBean.setListener(new LogbackShutdownListener());
        return registrationBean;
    }

    @Bean
    public FilterRegistrationBean<XssEscapeServletFilter> xssEscapeServletFilter(){
        FilterRegistrationBean<XssEscapeServletFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new XssEscapeServletFilter());
        registrationBean.addUrlPatterns("/*");
        registrationBean.setMatchAfter(true);
        return registrationBean;
    }
}
spring.profiles.active=@environment@
spring.config.import=classpath:common.properties, classpath:web.properties
server.servlet.encoding.charset=UTF-8
server.servlet.encoding.force=true


# https://www.baeldung.com/spring-mvc-content-negotiation-json-xml#basics-1 참고
spring.mvc.pathmatch.matching-strategy=ant-path-matcher
기존에 maven 사용하고 있었기 때문에 profile은 maven에서 변수로 넘겨받아 @environment@로 세팅.
[Spring] profile로 alpha, beta, real 빌드 구분하기

 

  • 마지막으로 기존 WebApplicationInitializer의 구현체를 아예 삭제해주고, SpringBootServletInitializer를 상속한 클래스를 만들어준다.
public class ServletInitializer extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }
}

 

여기까지 하고 기존처럼 외장 tomcat에서 애플리케이션 실행해본다. 서버 잘 뜨면 다음으로.

 

1-3. WebMvcConfigurer 최신화

  • EnableWebMvc와 WebMvcConfigurer 의 관계  
  • 기존에 WebMvcConfigurerAdapter를 상속하던 Bean이 있다면 이를 WebMvcConfigurer 구현으로 바꿔준다.
  • @EnableWebMvc는 삭제해준다.
  • viewResolver 설정, argumentResolver 설정을 최신화 해준다.
public class WebMvcConfigurerImpl implements WebMvcConfigurer {
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.jsp("/WEB-INF/{경로잡아준다}", ".jsp");
    }
    
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(myArgumentResolver);
    }

 

1-4. /build/ 로 접근했을 때 webapp/build/index.html 반환하도록 매핑하기

@Override
public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/build/").setViewName("forward:/build/index.html");
}

 

1-5. boot로 변경하면서 spring 4 -> 5로 버전업 했다면 호환성 체크

 

전환 1단계 끝.

생각 보다 간단하게 전환 할 수 있다.

이제 maven을 gradle로 전환한다거나, jsp를 걷어낸다거나, 내장 tomcat을 사용한다거나 하는 것들을 차차 진행하면 된다.

추가 내용 참고 - https://www.baeldung.com/spring-boot-migration