일일이 빈으로 등록하기 보다는 애노테이션 기반 스프링 MVC를 사용할 때 편리한 웹 MVC 기본 설정을 할 수 있다.
@Configuration
@EnableWebMvc
public class WebConfig {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
DelegatingWebMvcConfiguration.class를 보면 delegation 구조로 되어있기 때문에 손쉽게 기본 전략 객체(빈)을 커스터마이징할 수 있는 것이다.
@Configuration(proxyBeanMethods = false)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
}
WebMvcConfigurationSupport.class에 HandlerMapping, Interceptor, MessageConverter 등 빈들이 등록되어 있다. WebMvcConfigurationSupport.classs는 스프링부트가 나오기 전부터 있었던 클래스이다.
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
private static final boolean romePresent;
private static final boolean jaxb2Present;
private static final boolean jackson2Present;
private static final boolean jackson2XmlPresent;
private static final boolean jackson2SmilePresent;
private static final boolean jackson2CborPresent;
private static final boolean gsonPresent;
private static final boolean jsonbPresent;
static {
ClassLoader classLoader = WebMvcConfigurationSupport.class.getClassLoader();
romePresent = ClassUtils.isPresent("com.rometools.rome.feed.WireFeed", classLoader);
jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder", classLoader);
jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) &&
ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader);
jackson2SmilePresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", classLoader);
jackson2CborPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.cbor.CBORFactory", classLoader);
gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
jsonbPresent = ClassUtils.isPresent("javax.json.bind.Jsonb", classLoader);
}
classpath에 어떤 라이브러리가 있느냐에 따라 스프링 MVC 구성 요소를 직접 빈으로 등록하지 않아도 기본 전략 객체 빈(DispatchServlet.properties)을 커스터마이징 해준다.
@Configuration
@ComponentScan
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Bean
public ViewResolver viewResolver(){
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
public class WebApplication implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.setServletContext(servletContext); // 추가
context.register(WebConfig.class);
context.refresh();
DispatcherServlet dispatcherServlet = new DispatcherServlet(context);
ServletRegistration.Dynamic app = servletContext.addServlet("app", dispatcherServlet);
app.addMapping("/app/*");
}
}
또 실행시켜보면 @EnableWebMvc를 쓰기 이전과는 다르게 HandlerMappings의 우선순위가 1. RequestMappingHandlerMapping 2. BeanNameUrlMapping으로 조정되었고, HandlerAdpaters의 우선순위도 1. RequestMappingHandlerAdpater 2. HttpRequestHandlerAdapter 3. SimpleControllerHandlerAdater로 조정되어서 성능 상에서도 약간의 이점이 있을 수 있다.
참고