du.study기록공간

[Spring MVC] web.xml 사용하지 않고 Spring MVC를 사용해보자 본문

스프링

[Spring MVC] web.xml 사용하지 않고 Spring MVC를 사용해보자

du.study 2019. 10. 17. 23:10
728x90

최근 스프링을 사용하면서 web.xml에 설정을 하고 코딩을 하는경우가 아에 없어졌다. 사실 스프링부트가 상용화되는 요즘에 web.xml이 왠말인가... 당장 내가 쓰는 프로젝트의 모든 빈을 web.xml에 등록한다 생각하니 상상만으로 충분히 끔찍하다.

 

이번엔 web.xml을 사용하지 않고 MVC를 사용하는 케이스를 기록하려 합니다.

 

 

먼저 Spring Project 생성을 위하여 Intellij 에서 maven project를 생성 후, spring, servlet등에 대한 정보를 넣어줬습니다.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>do.spring</groupId>
    <artifactId>testProject</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>
    </dependencies>
</project>

 

web.xml을 사용하지 방법으로 SpringMVC를 구현하는 가장 기초적인 방법으로DispatcherServlet을 선언하여 사용하는 법을 가장 먼저 해보면, 가장 무식하게 떠오르는건.. DispatchServlet을 생성하는것..

 

 

간단하게 보면 아래의 세개의 class는 같은 package에 있다고 가정한다.(@ComponentScan 으로 Controller를 읽기위해)

public class WebBootstrap implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(WebConfig.class);
        ctx.refresh();

        DispatcherServlet dispatcherServlet = new DispatcherServlet(ctx);
        ServletRegistration.Dynamic app = servletContext.addServlet("doMVC", dispatcherServlet);
        app.addMapping("/*");
    }
}


@Configuration
@ComponentScan(basePackages = {"dodo"})
public class WebConfig{
}


@Controller
public class HelloController {

    @GetMapping("/hello")
    @ResponseBody
    public String hello() {
        return "Hello SpringMVC ";
    }
}

WebApplicationInitializer 라는 implement를 설정을 하게되면 서블릿 컨테이너가 구동중에 @Override된 onStartup을 호출하게 됩니다. 이 과정에서 context.setServletContext(servletContext); 를 등록했기에 WebConfig에 있는 설정을 읽어서 Controller를 등록하게 됩니다.

WebApplicationInitializer 는 스프링 3.1 이상, servlet 3.0 이상 지원을 해준다고 합니다.

 

지금까지 작성한 프로젝트 구조

 

하지만 이방법은 너무 밑바닥부터..하는작업이고 스프링 3.2 부터 나온 AbstractAnnotationConfigDispatcherServletInitializer 를 살펴보면

@Override
@Nullable
protected WebApplicationContext createRootApplicationContext() {
	Class<?>[] configClasses = getRootConfigClasses();
	if (!ObjectUtils.isEmpty(configClasses)) {
		AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
		context.register(configClasses);
		return context;
	}
	else {
		return null;
	}
}

내부적으로 위에서 명시했던 기능을 구현해주고 있고 AbstractAnnotationConfigDispatcherServletInitializer는 

AbstractDispatcherServletInitializer를 extends하고 있습니다. AbstractDispatcherServletInitializer안에서 onStartup이

호출이 되며 다음과 같이 registerDispatcherServlet 가 불리게됩니다.

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
	super.onStartup(servletContext);
	registerDispatcherServlet(servletContext);
}

registerDispatcherServlet 안에서 createDispatcherServlet를 부르게 되고, 이를 통해 DispatcherServlet이 생성되는 구조로 되어 있습니다.

FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext);

호출

protected FrameworkServlet createDispatcherServlet(WebApplicationContext servletAppContext) {
	return new DispatcherServlet(servletAppContext);
}

 

 

결론적으로 WebApplicationInitializer를 수정해보면

public class WebBootstrap extends AbstractAnnotationConfigDispatcherServletInitializer  {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] { RootConfig.class };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { WebConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
}

//RootC
@Configuration
public class RootConfig {
}

@Configuration
@ComponentScan(basePackages = {"dodo"})
public class WebConfig{
}

@Controller
public class HelloController {

    @RequestMapping("/hello")
    @ResponseBody
    public String hello() {
        return "Hello SpringMVC ";
    }
}

 다음과 같이 세팅 후, Controller를 호출하면 동일하게 동작을 하게됩니다.

 

getServletConfigClasses, getRootConfigClasses 이 각각 무슨기능인지 간락하게 살펴보면

getRootConfigClasses() 의 경우에는 ContextLoaderListener가 생성한 어플리케이션 컨텍스트를 설정하는데 사용되고,

getServletConfigClasses()의 경우 DispatcherServlet 사용되는 빈들을 등록합니다.

 

관련 코드 : https://github.com/Parkdusang/spring-test

728x90
Comments