Spring/Spring MVC

[Spring] Spring IoC Container 연동

TheWing 2020. 11. 7. 00:08

Spring IoC Container 연동

Servlet Application 에 Spring 연동하기

  • 서블릿에서 스프링이 제공하는 IoC 컨테이너 활용하는 방법
  • 스프링이 제공하는 서블릿 구현체 DispatcherServlet 사용하기

IoC 컨테이너 활용하는 예제

  • 의존성 추가
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>5.1.3.RELEASE</version>
</dependency>
  • web.xml 수정 기존 listener 제거후 아래 추가
<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
  • AppConfig 생성
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
public class AppConfig {

}
  • HelloService 생성
import org.springframework.stereotype.Service;

@Service
public class HelloService {
    public String getName() {
        return "TheWing";
    }
}
  • HelloServlet 생성
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.WebApplicationContext;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class HelloServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        ApplicationContext context = (ApplicationContext) getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
        HelloService helloService = context.getBean(HelloService.class);

        System.out.println("doGet");
        resp.getWriter().println("<html>");
        resp.getWriter().println("<head>");
        resp.getWriter().println("</head>");
        resp.getWriter().println("<body>");
        resp.getWriter().println("<h1>Hello, " + helloService.getName() + "</h1>");
        resp.getWriter().println("</body>");
        resp.getWriter().println("</html>");
    }

    private Object getName() {
        return getServletContext().getAttribute("name");
    }

    @Override
    public void destroy() {
        System.out.println("destroy");
    }

    @Override
    public void init() throws ServletException {
        System.out.println("init");
    }
}
  • 위에 WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTEApplicationContext 를 담고 있는 것이다
  • 결과

  • 결과는 동일하다

ContextLoaderListener

  • 서블릿 리스너 구현체
  • ApplicationContext를 만들어 준다
  • ApplicationContext를 서블릿 컨텍스트 라이프사이클에 따라 등록하고 소멸시켜준다
  • 서블릿에서 IoC 컨테이너를 ServletContext를 통해 꺼내 사용할 수 있다.

Serlvet의 단점

  • 하나하나 아래와 같이 URL 요청하나 할 때마다 하나의 서블릿을 지정해줘야해서 번거로움이 있다
  • 여러개 공통된 서블릿을 처리할때 filter로 처리할 수는 있긴하다
<servlet>
  <servlet-name>hello</servlet-name>
  <servlet-class>kr.thewing.HelloServlet</servlet-class>
</servlet>

<servlet-mapping>
  <servlet-name>hello</servlet-name>
  <url-pattern>/hello</url-pattern>
</servlet-mapping>

DispatcherServlet

  • 스프링 MVC의 핵심이다
  • 스프링이 분배를 해주고 Front Controller 역할을 해주는 서블릿을 구현해놓았다

Front Controller

DispatcherServlet

  • Servlet Context에 등록 되어있는 ApplicationContext를

Root WebApplicationContext

<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
  <servlet-name>hello</servlet-name>
  <servlet-class>kr.thewing.HelloServlet</servlet-class>
</servlet>
  • 이것이 Root WebApplicationContext이다
  • Root WebApplicationContext를 디스패처서블릿이 상속받는 애플리케이션 컨텍스트를 하나 더 만든다
  • 상속 관계를 만드는 이유는 ContextLoaderListener는 다른 서블릿이 공유해서 사용이 가능하다. 디스패처 서블릿이 만든 애플리케이션 컨텍스트는 그 안에서만 한정되어 있다.
    혹시라도 여러개의 서블릿을 만들 경우에 커버하기위해 상속구조를 만들었다.
  • RootWebApplicationContext는 웹과 관련된 빈들은 등록되지 않는다

결론

  • DispatcherServlet이 Servlet WebApplicationContext와 Root WebApplicationContext를 감싼다.
  • 스프링 MVC의 핵심이다
  • Servlet WebApplicationContext는 Web과 관련된 빈을 등록한다. Controller, ViewResolver, HandlerMapping
  • Root WebApplicationContext는 Web과 관련된 빈은 등록하지 않는다. Services, Repositories

Reference