1. Tomcat과 Spring Container의 주 요소
Spring에 대해서 처음 배울 때 가장 이해하기 어려웠던 부분이자 지금도 약간 헷갈리는 부분의 도식이다.
DispatcherServlet, DelegatingFilterProxy 둘 다 각각 Servlet, Filter 의 구현체이다.
관리 자체는 Servlet Container 관할이기에 왼쪽에 있지만, 구현체는 Spring Bean 이라는 것을 알아두어야 한다.
만약 순수하게 Spring만을 사용한다면, Spring Container에서 제공되는 WebApplicationContext,
즉 Bean의 생성과 주입까지는 우리가 Spring Boot환경에서 사용해왔던 것 처럼 사용이 가능하다.
그런데 이를 통해서 우리가 만들 수 있는 것은 서버 위에서 돌아갈 Application이지, 서버의 구축까지를 포함하지는 않는다.
빌드 시 산출물도 다르다. WAR까지는 구현이 되지만 JAR를 산출할 수는 없다. 서버가 내장되어있지는 않기 때문이다.
https://docs.spring.io/spring-boot/specification/executable-jar/nested-jars.html
그렇기에 Spring과 Spring Boot의 가장 큰 차이점 중 하나가 내장 Servlet Container,
대표적으로 Tomcat Server가 내장되어 있는가? 아닌가? 였다.
그렇다면 Spring에서 어떤 것을 추가해야 Tomcat이 될 수 있는지에 대해서 알아봐야 할 것 같다.
2. Web.xml : Spring에서 Tomcat 서버를 구성하기 위한 청사진
앞서 설명했듯, tomcat에서 servlet 을 인터페이스로,
구현체는 spring bean(정확히는 DispatcherServlet)으로 한것이 바로 Dispatcher Servlet이다.
같은 방식으로, Tomcat에서 Filter를 인터페이스로, 구현체는 spring bean(DelegateFilterProxy)으로 한 것이 같은 방식이다. 이때 구현체를 각각 DispatcherServlet, DelegateFilterProxy로 사용하도록 설정을 해줘야 하는데,
이러한 설정 파일을 넣는 곳이 바로 root 디렉토리의 web.xml이다.
xml파일은 html과 마찬가지로 마크업 언어를 표현한 파일이다.
html은 기본적으로 목적 자체가 문서(자료제공)를 위한 것이라면,
xml은 문서 뿐만이 아니라 다양한 형태의 데이터를 위한 마크업 언어라고 보면 된다.그리고 이와 같은 xml파일을 사용해서 설정하는 방식을 XML Schema-based Configuration이라 한다.https://docs.spring.io/spring-framework/docs/4.2.x/spring-framework-reference/html/xsd-configuration.html
현재 최근의 spring boot에서는 jakarta EE를 통한 서버를 구현하고 있는데,
이때 사용되는 xml은 https://jakarta.ee/xml/ns/jakartaee/
에서 제공되기는 한다. 근데 무지막지하게 길다!
GPT의 도움을 빌려서 몇 가지 중요한 Servlet에 대한 web.xml을 적어보겠다.
3. Tomcat 설정을 위한 주 요소의 xml파일 예시
우선, web.xml에 다음과 같이 중요 요소들에 대한 설정을 통합한 파일을 작성한다.
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<!-- 1. Servlet Context Listener (Spring ContextLoaderListener) -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 2. DispatcherServlet 등록 -->
<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/dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 3. DispatcherServlet 매핑 -->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 4. Character Encoding Filter 등록 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<!-- 5. Filter 매핑 -->
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
그리고 /WEB-INF/ 디렉토리에 내가 커스텀하고자 하는 dispatcher-servlet.xml과 같은 파일을 작성해주어야 한다.아래는 가장 기본적인 DispatcherServlet을 설정하는 dispatcher-servlet.xml의 예시이다.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
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
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 1. Component Scan -->
<context:component-scan base-package="com.example.web" />
<!-- 2. View Resolver -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- 3. Default Servlet Handling -->
<mvc:default-servlet-handler />
<!-- 4. Enable Spring MVC Annotations -->
<mvc:annotation-driven />
<!-- 5. Message Source for i18n -->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="messages" />
</bean>
<!-- 6. Interceptors -->
<mvc:interceptors>
<bean class="com.example.web.interceptor.LoggingInterceptor" />
</mvc:interceptors>
<!-- 7. Static Resource Handling -->
<mvc:resources mapping="/static/**" location="/static/" />
</beans>
4. Spring Boot와 Spring + web.xml의 차이?
그러면 Spring 어플리케이션에 web.xml을 작성한다면 그게 Spring Boot일까?
결과물, 즉 돌아가는 기능 상으로는 그렇다고 할 수 있지만
Spring Boot라고 볼 수는 없는데, 그 이유는 아래와 같다.
- 가장 중요한 차이점은 Spring Boot에서는 더 이상 web.xml을 통한 서버의 구현을 하지 않는다.
- Spring Boot에서는 web.xml과 같은 서버의 설정 파일을 사용하지 않고,
Java Config와 어노테이션을 사용해 서버를 구성한다. - 즉, @SpringBootApplication을 통해서 서버를 구현한다.
- 참고로, @SpringBootApplication
= @SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScan 으로 구성- @SpringBootConfiguration : Spring Boot를 통한 서버의 default 설정 + @Configuration 역할
- @EnableAutoConfiguration : classpath기반 (Build된 산출물의 class파일에 대한 경로) 의존성 추가
- @ComponentScan : 해당 어노테이션이 있는 하위 패키지에 있는 @Component들을 매핑하고 Spring Container에 등록한다.
- 참고로, @SpringBootApplication
- Spring Boot에서는 web.xml과 같은 서버의 설정 파일을 사용하지 않고,
- 이렇게 해서 만들어진 Tomcat 서버는 하나의 서버 구현 방식일 뿐이며,
실제 Spring Boot는 netty 등 다양한 내장 서버기능을 제공한다. - Spring의 경우, 라이브러리 간 의존성을 추가적으로 관리해주어야 하지만,
Spring Boot는 starter-pack을 통해서 의존성이 관리되어있는 버전을 사용하기에 이에 대한 부담이 적은 편이다.
5. Spring Boot 환경에서 Bean의 customizing
Spring Boot 환경에서 권장되는 Bean의 customizing 방법은 @Configure와 @Bean을 사용한
Java Based Config 이다. https://docs.spring.io/spring-framework/reference/core/beans/java/bean-annotation.html#beans-java-customizing-bean-naming
방법은 심플하고, 이미 알고 있던 방식과 같다.
@Configuration
public class AppConfig {
@Bean
public TransferServiceImpl transferService() {
return new TransferServiceImpl();
}
}
와 같은 방식으로 Bean을 정의하면 알아서 주입된다.
다만 기존의 방식이었다면 아마
<beans>
<bean id="transferService" class="com.acme.TransferServiceImpl"/>
</beans>
xml 파일에 위와 같은 bean 설정을 추가해주어야 할 것이다.
'연재작 > WEB - BE' 카테고리의 다른 글
Spring Bean Deep Dive (0) | 2024.12.02 |
---|---|
디렉토리 구조와 Facade 패턴 (1) | 2024.11.19 |
JVM Runtime Data Area, Singleton과 Race Condition (1) | 2024.11.15 |
Spring bean (3) - 의존성 주입, Spring Framework의 의존성 관리 (0) | 2024.10.23 |
Spring bean (2) - Singleton, Bean (0) | 2024.10.11 |