<청춘> 격정적으로 사는 것

밤을 새고 공부한 다음 날 새벽에 느꼈던 생생한 환희와 야생적인 즐거움을 잊을 수 없다

BOOK REVIEW/실전 스프링 부트 워크북

[실전 스프링 부트 워크북] CH5. 스프링과 스프링 부트

수학도 2021. 8. 15. 15:52

CH5 스프링과 스프링 부트

5.1 스프링 웹 애플리케이션 

    5.1.1 J2EE 웹 애플리케이션

    5.1.2 스프링 MVC 애플리케이션

    5.1.3 스프링 부트 웹 애플리케이션

5.2 스프링 부트에서 스프링을!

    5.2.1 XML 구성 가져오기

5.3 스프링 부트에서 스프링 기술 활용

 

 

  • 5.1 : 웹 애플리케이션을 개발하는 전통 스프링 MVC 방식과 새로운 스프링 부트 방식의 차이점
  • 5.2 : XML 파일 또는 자바 구성 애너테이션으로 기존 스프링 앱을 스프링 부트에서 사용하는 방법
  • 5.3 : 모든 스프링 기술은 @Enable<기술명> 애너테이션만 있으면 간단히 불러 쓸 수 있다.

 


 

기존 스프링 앱 개발 방식과 스프링 부트의 새로운 개발 방식을 서로 비교하고 레거시 코드를 스프링 부트 앱으로 전환하는 문제를 다뤄보자.

 

 

5.1 스프링 웹 애플리케이션

5.1.1 J2EE 웹 애플리케이션

옛날 방식으로, 서블릿 2.4 명세와 메이븐 아키타입을 응용해서 J2EE 웹 애플리케이션을 작성해보자. 

서블릿은 서버측에 HTML을 요청하는 첫 관문이다.

 

 

① 메이븐 실행 파일의 경로를 PATH에 추가하고 다음 명령으로 웹 프로젝트 템플릿을 생성한다.

$ mvn archetype:generate -DgroupId=com.apress.j2ee -DartifactId=simple-web-app -DarchetypeArtifactId=maven-archetype-webapp

 

실행이 끝나면 다음과같은 simple-web-app 폴더 구조가 만들어진다.

 

 

② 폼(pom.xml) 파일에 빠진 부분을 채워 넣는다.

<dependency>
	<groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>2.4</version>
    <scope>provided</scope>
</dependency>

서블릿 클래스를 작성할 때 꼭 필요한 servlet-api를 <dependencies></dependencies> 태그 안에 넣어준다.

<packaging>war</packaging>

이 프로젝트를 WAR(웹 아카이브) 파일로 배포할 거란 사실을 메이븐에 알리는 <packaging> 태그도 추가한다.

 

 

③ 서블릿 - SimpleServlet 클래스

package com.apress.j2ee;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class SimpleServlet extends HttpServlet {
	
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    	PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<body>");
        out.pintln("<h1>간단한 자바 웹 애플리케이션</h1>");
        out.println("</body>");
        out.println("</html>");
    }

}
  • SimpleServlet 클래스는 HttpServlet 을 상속한다.
  • service 메서드는 PrintWriter 클래스(java.io.PrintWriter)로 응답 메시지를 준비한다.
  • 어떤 URL 패턴을 이 서블릿 클래스로 보낼지는 WEB-INF 폴더에 위치한 web.xml 파일에 적는다. 즉, src/webapp/WEB-INF/web.xml 파일을 열어 서블릿을 선언해야 한다.

 

④ src/webapp/WEB-INF/web.xml 파일

<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
	<display-name>Archetype Created Web Application</display-name>
	<servlet>
		<servlet-name>SimpleServlet</servlet-name>
    	<display-name>SimpleServlet</display-name>
    	<description>간단한 서블릿</description>
    	<servlet-class>com.apress.j2ee.SimpleServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>SimpleServlet</servlet-name>
    	<url-pattern>/SimpleServlet</url-pattern>
	</servlet-mapping>
</web-app>
  • <servlet> 태그에서 서블릿명을 선언 - ③에서 서블릿 이름이 SimpleServlet이니까 이걸 넣어주면 됨
  • <servlet-mapping> 태그에서 요청끝점에 해당하는 URL로 서블릿을 매핑

 

⑤ 웹 애플리케이션 패키징

$ mvn clean package
  • target/ 폴더에 simple-web-app.war 파일이 생성된다.
  • WAR 파일을 <톰캣 설치 경로>/webapps/에 올려놓고, <톰캣 설치 경로>/bin에 있는 startup.sh 스크립트를 실행하여 서버를 실행해보자.
  • 그 다음 웹 브라우저를 열고 http://localhost:8080/simple-web-app/SimpleServlet 에 접속하면 서블릿에 service 메서드 안에 내용이 화면에 텍스트로 출력된다.

출력 결과

  • 간단한 자바 웹 애플리케이션

 


 

서블릿 탄생 이후 JSP(자바 서버 페이지)가 고안됐고, 그 이후로도 J2EE는 더욱 진화했다.

서블릿 3 명세부터는 web.xml 없이 @WebServlet 애너테이션을 붙여서 웹 애플리케이션을 개발할 수 있게 발전했다.

 


5.1.2 스프링 MVC 애플리케이션

스프링 프레임워크는 설정 및 사용이 간편한 MVC(모델-뷰-컨트롤러) 패턴을 도입함으로써 웹 애플리케이션 개발을 더욱 발전시켰다. 

 

스프링 MVC 앱에 대해 설명하기 위해 5.1.1에서의 메이븐 아키타입을 그대로 사용해보자.

 

① 메이븐 실행 파일의 경로를 PATH에 추가하고 다음 명령으로 웹 프로젝트 템플릿을 생성한다.

$ mvn archetype:generate -DgroupId=com.apress.j2ee -DartifactId=simple-web-app -DarchetypeArtifactId=maven-archetype-webapp

위의 코드로 생성된 프로젝트는 옛날 버전이기 때문에 약간의 수정이 필요하다.

 

 

② 폼(pom.xml) 파일을 수정하자.

<properties>

	<!-- 일반 프로퍼티 -->
    <java.version>1.8</java.version>
    
    <!-- 웹 -->
    <jsp.version>2.2</jsp.version>
    <jstl.version>1.2</jstl.version>
    <servlet.version>2.5</servlet.version>
    <!-- 스프링 -->
    <spring-framework.version>3.2.3.RELEASE</spring-framework.version>
    
</properties>

<dependencies>

	<!-- 스프링 MVC -->
    <dependency>
    	<groupId>org.springframework</groupId>
        <artifactId>spring-framework</artifactId>
        <version>${spring-framwork.version}</version>
    </dependency>
    
    <!-- 기타 웹 의존체 -->
    <dependency>
    	<groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>${jstl.version}</version>
   	</dependency>
    <dependency>
    	<groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>${servlet.version}</version>
        <scope>provided</scope>
   	</dependency>
    <dependency>
    	<groupId>javax.servlet.jsp</groupId>
        <artifactId>jsp-api</artifactId>
        <version>${jsp.version}</version>
        <scope>provided</scope>
   	</dependency>
    
</dependencies>

<build>
	<finalName>simple-web-spring-app</finalName>
</build>
  • 스프링 MVC 3.2.3.RELEASE 버전과 그 라이브러리 등 관련 의존체(jstl, jsp-api 등)가 포함됐다.

 

 

③ src/main/webapp/WEB-INF/web.xml 파일

서블릿 2.5 명세를 사용하려면 web.xml 버전을 2.3에서 2.5로 바꿔야 한다. J2EE에서 아주 성가신 일 중 하나이다.

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http:java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    id="WebApp_ID" version="2.5">
    
	<display-name>simple-web-spring-app</display-name>

	<servlet>
		<servlet-name>dispatcherServlet</servlet-name>
    	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    	<init-param>
    		<param-name>contextConfigLocation</param-name>
        	<param-value>/WEB-INF/mvc-config.xml</param-value>
    	</init-param>
   	 	<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>dispatcherServlet</servlet-name>
    	<url-pattern>/</url-pattern>
	</servlet-mapping>
</web-app>
  • 버전이 2.5 (서블릿 엔진 버전)로 변경됐다.
  • org.springframework.web.servlet.DispatcherServlet 클래스를 메인 디스패처로 추가해서 MVC 패턴을 걸었다.
  • <init-param> 태그에서 contextConfigLocation 파라미터 값으로 지정한 WEB-INF/mvc-config.xml은 스프링이 찾는 XML 구성 파일로, 스프링 컨텍스트를 구성하는 파일이기도 하다.

 

④ src/main/webapp/WEB-INF/mvc-config.xml 파일

컨테이너에 초기화할 스프링 빈을 정의하는 전형적인 스프링 구성 파일

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="htttp://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">

	<bean name="/showMessage.html" class="com.apress.spring.SimpleController" />

	<bean class="org.springframework.web.servlet.view.InternalResourceViesResolver">
		<property name="prefix" value="/WEB-INF/view/" />
    		<property name="suffix" value=".jsp" />
	</bean>

</beans>
  • 이름이 /showMessage.html인 빈을 com.apress.spring.SimpleController라는 자바 클래스와 엮었다. - 클라이언트가 /showMessage.html URL로 요청하면 이 클래스를 실행하라는 의미이다.
  • InternalResourceViewResolver 클래스로 뷰 리졸버를 선언했다. - 여기선 모든 뷰 파일이 /WEB-INF/view에 있고 각 페이지엔 .jsp 확장자를 붙인다는 의미이다.

 

⑤ 컨트롤러 - com.apress.spring.SimpleController 클래스

요청(/showMessage.html)을 처리하는 로직이 모두 담긴 추상 클래스 AbstractController를 확장한 클래스이다.

package com.apress.spring;

import javax.servlet.http.httpServletRequest;
import javax.servlet.http.httpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;

public class SimpleController extends AbstractController {

	@Override
    protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
    	
        ModelAndView model = new ModelAndView("showMessage");
        model.addObject("message", "스프링 MVC 웹 애플리케이션");
        
        return model;
    }

}
  • handleRequestInternal 메서드를 재정의(@Override)해서 화면에 표시할 뷰 정보가 담긴 ModelAndView 인스턴스를 반환하는 것으로 클라이언트에 응답한다. 이 인스턴스는 message 변수에 '스프링 MVC 웹 애플리케이션'이라는 문자열을 실어 나른다.
  •  ModelAndView model = new ModelAndView("showMessage"); 선언을 통해 스프링 MVC는 실제로 렌더링할 뷰가 showMessage라고 인식한다. 이 뷰가 바로 /WEB-INF/view/showMessage.jsp 파일이고, 페이지로 보여주는 일은 mvc-config.xml 파일에 있는 InternalResourceViewResolver 클래스가 수행한다.

 

 

⑥ 뷰 - src/main/webapp/WEB-INF/view/showMessage.jsp

<!DOCTYPE html>

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>

<html>
	<head>
    	<meta charset="utf-8">
        <title>환영합니다</title>
    </head>
    <body>
    	<h2>${message}</h2>
    </body>
</html>
  • <h2>태그 안에 있는 ${message}값은 컨트롤러에서 model 인스턴스에 담아둔 message 변수의 값을 가져온다. 즉, ${message}값이 "스프링 MVC 애플리케이션"이란 문자열로 바뀐다.

 

 

⑦ 앱 패키징 후 서버에 배포

$ mvn clean package
  • 앱을 패키징하면 target/simple-web-spring-app.war 파일이 생성된다.
  • 이 파일을 서버에 배포한 후, http://localhost:8080/simple-web-spring-app/showMessage.html에 접속해보자.
  • 화면에 "스프링 MVC 애플리케이션"이 보이면 성공적으로 수행된 것이다.

 

간단한 스프링 MVC 애플리케이션 완성!


 

스프링 MVC 2.5, 3, 4 버전부터는 다른 클래스를 상속하거나 한 클래스에 여러 가지를 매핑하지 않아도 애너테이션만 붙여 개발이 가능하다.

 

 

⑧ 애너테이션을 사용한 컨트롤러 - com.apress.spring.SimpleController 클래스

package com.apress.spring;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("/showMessage.html")
public class SimpleController {

	@RequestMapping(method=RequestMethod.GET)
    public ModelAndView helloWorld() {
    	
        ModelAndView model = new ModelAndView("showMessage");
        model.addObject("message", "애너테이션을 사용한 스프링 MVC 웹 애플리케이션");
        
        return model;
    }

}

 

 

⑨ src/main/webapp/WEB-INF/mvc-config.xml 파일

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="htttp://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">

	<context:component-scan base-pacakage="com.apress.spring" />

	<bean class="org.springframework.web.servlet.view.InternalResourceViesResolver">
		<property name="prefix" value="/WEB-INF/view/" />
    		<property name="suffix" value=".jsp" />
	</bean>

</beans>
  • <context:component-scan> 태그는 스프링으로 하여금 com..apress.spring 패키지 레벨에서 애너테이션으로 표시한 클래스를 찾게한다.

 


 

5.1.3 스프링 부트 웹 애플리케이션

 

① simple-web-spring-boot 폴더 생성 후 스프링 부트 웹 프로젝트 생성

$ mkdir simple-web-spring-boot
$ cd simple-web-spring-boot
$ spring init -d=web -g=com.apress.spring -a=simple-web-spring-boot --pacakage-name=com.apress.spring -name=simple-web-spring-boot -x
  • -d=web : 웹 관련 의존체(spring-boot-starter-web) 포함
  • -g : 그룹 이름
  • -a : 아티팩트 ID
  • --package-name : 패키지명
  • -name : 애플리케이션명
  • -x : 현재 폴더에 템플릿 압축 파일 풀기

 

② 메인 클래스 - com.apress.spring.SimpleWebSpringBootApplication 클래스

package com.apress.spring;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;

@RestController
@SpringBootApplication
public class SimpleWebSpringBootApplication {

	@RequestMapping("/showMessage.html")
    public String index() {
    	return "스프링 부트 시작!";
    }

	public static void main(String[] args){
    	SpringApplication.run(SimpleWebSpringBootApplication.class, args);
    }
}
  • @RestController 애너테이션을 붙여 웹 REST 컨트롤러임을 알린다.
  • @RequestMapping 애너테이션을 붙여 /showMessage.html 요청을 index 메서드가 처리하게 한다.
  • @SpringBootApplication 애너테이션은 SpringApplication.run으로 실행하는 main 메서드와 클래스패스를 기반으로 앱을 자동 구성한다.

 

③ 실행

앱이 시동하면 내장 톰캣 서버도 함께 실행되고 8080 포트를 리스닝한다.

$ ./mvnw spring-boot:run

위의 명령으로 앱을 실행하고 브라우저 주소 창에 http://localhost:8080/showMessage.html을 입력하자.

화면에 "스프링 부트 시작!" 이라고 보이면 성공적으로 수행된 것이다.

 

 

결론

5.1.1에서는 옛 자바로, 5.1.2에서는 스프링 MVC로, 5.1.3에서는 스프링 부트로 웹 애플리케이션을 만들어보았다. 이 과정에서 셋을 비교해보자면, 스프링 MVC는 여전히 스프링 부트 웹 애플리케이션의 기본 틀이지만, 스프링 부트는 개발 과정이 훨씬 간편하고 구성 파일을 없앴다는 것이 기존 자바/ 스프링 MVC와 구별되는 점이다. 즉, 스프링 부트는 XML 파일을 상대할 필요가 없는 것이다.

 

 


5.2 스프링 부트에서 스프링을!

 

스프링 컨테이너와 구성을 살펴보고 스프링 부트에 통합하는 과정을 알아보자.

 

스프링

초기 스프링 프레임워크는 XML 구성 파일에 지나치게 의존했다. 자바 5 출시 이후 자바 클래스(애너테이션)로도 구성할 수 있게 되면서 @Configuration 및 @Bean으로 스프링 컨테이너를 구성하게 되었다. 

 

스프링 부트

스프링 부트도 마찬가지로 XML 파일이건 애너테이션이건 어느 쪽이든 가능하다.

 

 

5.2.1 XML 구성 가져오기

 

XML 구성 파일이 여럿 있으면 메인 애플리케이션에서 애너테이션 하나로 합칠 수 있다. 각 XML 구성 파일의 경로와 이름을 org.springframework.context.annotation.ImportResource 애너테이션에 String 배열 형태로 넘기면 된다.

 

스프링 부트 앱에서는 기존 메인 스프링 부트 앱의 XML 구성 파일(또는 자바 구성 클래스)을 아래와 같이 쓰면 된다.

@ImportResource({"META-INF/spring/services-context.xml", "META-INF/spring/repositories-context.xml"})
@SpringBootApplication
public class SpringXMLApplication {
	...
}

 

혹은 기존 자바 구성 클래스에서 XML 구성 파일을 재사용할 수도 있다.

@ImportResource("classpath:applicationContext.xml")
@Configuration
public class SimpleConfiguration [
	...
}

 

혹은 main 메서드에서 XML 파일을 불러올 수도 있다.

public class Application {
	public static void main(String[] args) throws Exception {
    	ConfigurableApplicationContext ctx = new SpringApplication("/META-INF/spring/integration.xml").run(args);
    	...
    }
}

 


 

5.3 스프링 부트에서 스프링 기술 활용

 

스프링 부트는 결국 스프링이고 XML 파일이나 자바 구성 클래스에서 선언한 빈을 자유롭게 사용할 수 있다.

따라서 스프링 프레임워크 4 버전부터 새로 등장한 애너테이션을 이용한 자동 구성을 통해 스프링 JMS, 스프링 AMQP, 스프링 통합, 스프링 캐싱, 스프링 세션, 스프링 REST 등 다른 스프링 기술을 스프링 부트에서 불러 쓸 수 있다. 

 

위의 각 기술마다 @Enable<기술명> 애너테이션을 하나씩 갖고 있다.

애너테이션 설명
@EnalbeJms JMS 메시징
@EnableCaching 캐시 추상화
@EnableRabbit 래빗MQ로 AMQP 메시징
@EnableBatchProcessing 스프링 배치
@EnableWebSecurity 스프링 시큐리티
@EnableRedisHttpSession 스프링 세션
@EnableJpaRepositories 스프링 데이터
@EnableIntegration 스프링 통합