내맘대로 스프링

WebMvcAutoConfiguration

yoon9 2023. 2. 26. 21:48

WebMvcAutoConfiguration은 스프링부트를 사용하여 autoconfiguration을 적용하여 사용될때 스프링이 WebMvc에 관련된 설정인데 이제 사실 사용자가 애플리케이션 빈을 등록을 할때는 프론트단에 관련된 빈은  @Controller만 등록을 한 경우가 대부분인데 (추후에 나중에 interceptor, filter를 추가하는 경우말고)

암튼 바로 컴파일 후에 실행만 하면 디스패처 서블릿으로 바로 요청과 응답이 된다.

 

원래 로직인 RequestMapping , HandlerAdapter등등.. 빈으로 다 등록이 자동으로 되어있는데 이것은

일단 org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration에 자동설정에 따라 등록이 기본적으로 된다.

 

그다음에는 스프링부트에서 exceptionHandler나 converter,formatter 등등을 확장을 하는 경우가 있을텐데 이것은 

WebMvcConfigurer 을 구현하여서 확장이나 재설정을 할 수 있다.

 

public interface WebMvcConfigurer {
    default void configurePathMatch(PathMatchConfigurer configurer) {
    }

    default void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    }

    default void configureAsyncSupport(AsyncSupportConfigurer configurer) {
    }

    default void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
    }

    default void addFormatters(FormatterRegistry registry) {
    }

    default void addInterceptors(InterceptorRegistry registry) {
    }

    default void addResourceHandlers(ResourceHandlerRegistry registry) {
    }

    default void addCorsMappings(CorsRegistry registry) {
    }

    default void addViewControllers(ViewControllerRegistry registry) {
    }

    default void configureViewResolvers(ViewResolverRegistry registry) {
    }

    default void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
    }

    default void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {
    }

    default void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    }

    default void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
    }

    default void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
    }

    default void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
    }

    @Nullable
    default Validator getValidator() {
        return null;
    }

    @Nullable
    default MessageCodesResolver getMessageCodesResolver() {
        return null;
    }
}

입맛에 맡게(?) 사용자 설정을 하면된다.

근데 여기서 추가로  RequestMapping , HandlerAdapter는 어디서 재정의나 뭐 어떻게 할 수 있을까..?

WebMvcRegistrations 을 이용하여 할 수 있다.

public interface WebMvcRegistrations {
    default RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
        return null;
    }

    default RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() {
        return null;
    }

    default ExceptionHandlerExceptionResolver getExceptionHandlerExceptionResolver() {
        return null;
    }
}

 

or

@Configuration
public class SimpleRequestMappingHandlerMapping {
    @Bean
    public WebMvcRegistrations webMvcRegistrations() {
        return new WebMvcRegistrations() {
            @Override
            public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
                return new SimpleRequestMappingHandlerMapping("simple");
            }
        };
    }
}

 

 

그러면 개발자가 완벽히 제어를 하는 방법은 뭘까

 

@EnableWebMvc 를 사용하는 경우이다.

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({DelegatingWebMvcConfiguration.class})
public @interface EnableWebMvc {
}

 

@Configuration(
    proxyBeanMethods = false
)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
    private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();

    public DelegatingWebMvcConfiguration() {
    }

    @Autowired(
        required = false
    )
    public void setConfigurers(List<WebMvcConfigurer> configurers) {
        if (!CollectionUtils.isEmpty(configurers)) {
            this.configurers.addWebMvcConfigurers(configurers);
        }

    }

    protected void configurePathMatch(PathMatchConfigurer configurer) {
        this.configurers.configurePathMatch(configurer);
    }

    protected void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        this.configurers.configureContentNegotiation(configurer);
    }

    protected void configureAsyncSupport(AsyncSupportConfigurer configurer) {
        this.configurers.configureAsyncSupport(configurer);
    }

    protected void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        this.configurers.configureDefaultServletHandling(configurer);
    }

    protected void addFormatters(FormatterRegistry registry) {
        this.configurers.addFormatters(registry);
    }

    protected void addInterceptors(InterceptorRegistry registry) {
        this.configurers.addInterceptors(registry);
    }

    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        this.configurers.addResourceHandlers(registry);
    }

    protected void addCorsMappings(CorsRegistry registry) {
        this.configurers.addCorsMappings(registry);
    }

    protected void addViewControllers(ViewControllerRegistry registry) {
        this.configurers.addViewControllers(registry);
    }

    protected void configureViewResolvers(ViewResolverRegistry registry) {
        this.configurers.configureViewResolvers(registry);
    }

    protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        this.configurers.addArgumentResolvers(argumentResolvers);
    }

    protected void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
        this.configurers.addReturnValueHandlers(returnValueHandlers);
    }

    protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        this.configurers.configureMessageConverters(converters);
    }

    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        this.configurers.extendMessageConverters(converters);
    }

    protected void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
        this.configurers.configureHandlerExceptionResolvers(exceptionResolvers);
    }

    protected void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
        this.configurers.extendHandlerExceptionResolvers(exceptionResolvers);
    }

    @Nullable
    protected Validator getValidator() {
        return this.configurers.getValidator();
    }

    @Nullable
    protected MessageCodesResolver getMessageCodesResolver() {
        return this.configurers.getMessageCodesResolver();
    }

WebMvcConfigurationSupport를 상속을 받고 있다.

public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
    private static final boolean shouldIgnoreXml = SpringProperties.getFlag("spring.xml.ignore");
    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;
    private static final boolean kotlinSerializationJsonPresent;
    @Nullable
    private ApplicationContext applicationContext;
    @Nullable
    private ServletContext servletContext;
    @Nullable
    private List<Object> interceptors;
    @Nullable
    private PathMatchConfigurer pathMatchConfigurer;
    @Nullable
    private ContentNegotiationManager contentNegotiationManager;
    @Nullable
    private List<HandlerMethodArgumentResolver> argumentResolvers;
    @Nullable
    private List<HandlerMethodReturnValueHandler> returnValueHandlers;
    @Nullable
    private List<HttpMessageConverter<?>> messageConverters;
    @Nullable
    private Map<String, CorsConfiguration> corsConfigurations;
    @Nullable
    private AsyncSupportConfigurer asyncSupportConfigurer;

    public WebMvcConfigurationSupport() {
    }

    public void setApplicationContext(@Nullable ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @Nullable
    public final ApplicationContext getApplicationContext() {
        return this.applicationContext;
    }

    public void setServletContext(@Nullable ServletContext servletContext) {
        this.servletContext = servletContext;
    }

    @Nullable
    public final ServletContext getServletContext() {
        return this.servletContext;
    }

    @Bean
    public RequestMappingHandlerMapping requestMappingHandlerMapping(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager, @Qualifier("mvcConversionService") FormattingConversionService conversionService, @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
        RequestMappingHandlerMapping mapping = this.createRequestMappingHandlerMapping();
        mapping.setOrder(0);
        mapping.setInterceptors(this.getInterceptors(conversionService, resourceUrlProvider));
        mapping.setContentNegotiationManager(contentNegotiationManager);
        mapping.setCorsConfigurations(this.getCorsConfigurations());
        PathMatchConfigurer pathConfig = this.getPathMatchConfigurer();
        Boolean useTrailingSlashMatch;
        if (pathConfig.getPatternParser() != null) {
            mapping.setPatternParser(pathConfig.getPatternParser());
        } else {
            mapping.setUrlPathHelper(pathConfig.getUrlPathHelperOrDefault());
            mapping.setPathMatcher(pathConfig.getPathMatcherOrDefault());
            useTrailingSlashMatch = pathConfig.isUseSuffixPatternMatch();
            if (useTrailingSlashMatch != null) {
                mapping.setUseSuffixPatternMatch(useTrailingSlashMatch);
            }

            Boolean useRegisteredSuffixPatternMatch = pathConfig.isUseRegisteredSuffixPatternMatch();
            if (useRegisteredSuffixPatternMatch != null) {
                mapping.setUseRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch);
            }
        }

        useTrailingSlashMatch = pathConfig.isUseTrailingSlashMatch();
        if (useTrailingSlashMatch != null) {
            mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
        }

        if (pathConfig.getPathPrefixes() != null) {
            mapping.setPathPrefixes(pathConfig.getPathPrefixes());
        }

        return mapping;
    }

    protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
        return new RequestMappingHandlerMapping();
    }

    protected final Object[] getInterceptors(FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
        if (this.interceptors == null) {
            InterceptorRegistry registry = new InterceptorRegistry();
            this.addInterceptors(registry);
            registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService));
            registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider));
            this.interceptors = registry.getInterceptors();
        }

        return this.interceptors.toArray();
    }

    protected void addInterceptors(InterceptorRegistry registry) {
    }

    protected PathMatchConfigurer getPathMatchConfigurer() {
        if (this.pathMatchConfigurer == null) {
            this.pathMatchConfigurer = new PathMatchConfigurer();
            this.configurePathMatch(this.pathMatchConfigurer);
        }

        return this.pathMatchConfigurer;
    }

    protected void configurePathMatch(PathMatchConfigurer configurer) {
    }

    @Bean
    public PathPatternParser mvcPatternParser() {
        return this.getPathMatchConfigurer().getPatternParserOrDefault();
    }

    @Bean
    public UrlPathHelper mvcUrlPathHelper() {
        return this.getPathMatchConfigurer().getUrlPathHelperOrDefault();
    }

    @Bean
    public PathMatcher mvcPathMatcher() {
        return this.getPathMatchConfigurer().getPathMatcherOrDefault();
    }

    @Bean
    public ContentNegotiationManager mvcContentNegotiationManager() {
        if (this.contentNegotiationManager == null) {
            ContentNegotiationConfigurer configurer = new ContentNegotiationConfigurer(this.servletContext);
            configurer.mediaTypes(this.getDefaultMediaTypes());
            this.configureContentNegotiation(configurer);
            this.contentNegotiationManager = configurer.buildContentNegotiationManager();
        }

        return this.contentNegotiationManager;
    }

    protected Map<String, MediaType> getDefaultMediaTypes() {
        Map<String, MediaType> map = new HashMap(4);
        if (romePresent) {
            map.put("atom", MediaType.APPLICATION_ATOM_XML);
            map.put("rss", MediaType.APPLICATION_RSS_XML);
        }

        if (!shouldIgnoreXml && (jaxb2Present || jackson2XmlPresent)) {
            map.put("xml", MediaType.APPLICATION_XML);
        }

        if (jackson2Present || gsonPresent || jsonbPresent) {
            map.put("json", MediaType.APPLICATION_JSON);
        }

        if (jackson2SmilePresent) {
            map.put("smile", MediaType.valueOf("application/x-jackson-smile"));
        }

        if (jackson2CborPresent) {
            map.put("cbor", MediaType.APPLICATION_CBOR);
        }

        return map;
    }

    protected void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    }

    @Bean
    @Nullable
    public HandlerMapping viewControllerHandlerMapping(@Qualifier("mvcConversionService") FormattingConversionService conversionService, @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
        ViewControllerRegistry registry = new ViewControllerRegistry(this.applicationContext);
        this.addViewControllers(registry);
        AbstractHandlerMapping handlerMapping = registry.buildHandlerMapping();
        if (handlerMapping == null) {
            return null;
        } else {
            PathMatchConfigurer pathConfig = this.getPathMatchConfigurer();
            if (pathConfig.getPatternParser() != null) {
                handlerMapping.setPatternParser(pathConfig.getPatternParser());
            } else {
                handlerMapping.setUrlPathHelper(pathConfig.getUrlPathHelperOrDefault());
                handlerMapping.setPathMatcher(pathConfig.getPathMatcherOrDefault());
            }

            handlerMapping.setInterceptors(this.getInterceptors(conversionService, resourceUrlProvider));
            handlerMapping.setCorsConfigurations(this.getCorsConfigurations());
            return handlerMapping;
        }
    }

    protected void addViewControllers(ViewControllerRegistry registry) {
    }

    @Bean
    public BeanNameUrlHandlerMapping beanNameHandlerMapping(@Qualifier("mvcConversionService") FormattingConversionService conversionService, @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
        BeanNameUrlHandlerMapping mapping = new BeanNameUrlHandlerMapping();
        mapping.setOrder(2);
        PathMatchConfigurer pathConfig = this.getPathMatchConfigurer();
        if (pathConfig.getPatternParser() != null) {
            mapping.setPatternParser(pathConfig.getPatternParser());
        } else {
            mapping.setUrlPathHelper(pathConfig.getUrlPathHelperOrDefault());
            mapping.setPathMatcher(pathConfig.getPathMatcherOrDefault());
        }

        mapping.setInterceptors(this.getInterceptors(conversionService, resourceUrlProvider));
        mapping.setCorsConfigurations(this.getCorsConfigurations());
        return mapping;
    }

    @Bean
    public RouterFunctionMapping routerFunctionMapping(@Qualifier("mvcConversionService") FormattingConversionService conversionService, @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
        RouterFunctionMapping mapping = new RouterFunctionMapping();
        mapping.setOrder(3);
        mapping.setInterceptors(this.getInterceptors(conversionService, resourceUrlProvider));
        mapping.setCorsConfigurations(this.getCorsConfigurations());
        mapping.setMessageConverters(this.getMessageConverters());
        PathPatternParser patternParser = this.getPathMatchConfigurer().getPatternParser();
        if (patternParser != null) {
            mapping.setPatternParser(patternParser);
        }

        return mapping;
    }

    @Bean
    @Nullable
    public HandlerMapping resourceHandlerMapping(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager, @Qualifier("mvcConversionService") FormattingConversionService conversionService, @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
        Assert.state(this.applicationContext != null, "No ApplicationContext set");
        Assert.state(this.servletContext != null, "No ServletContext set");
        PathMatchConfigurer pathConfig = this.getPathMatchConfigurer();
        ResourceHandlerRegistry registry = new ResourceHandlerRegistry(this.applicationContext, this.servletContext, contentNegotiationManager, pathConfig.getUrlPathHelper());
        this.addResourceHandlers(registry);
        AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();
        if (handlerMapping == null) {
            return null;
        } else {
            if (pathConfig.getPatternParser() != null) {
                handlerMapping.setPatternParser(pathConfig.getPatternParser());
            } else {
                handlerMapping.setUrlPathHelper(pathConfig.getUrlPathHelperOrDefault());
                handlerMapping.setPathMatcher(pathConfig.getPathMatcherOrDefault());
            }

            handlerMapping.setInterceptors(this.getInterceptors(conversionService, resourceUrlProvider));
            handlerMapping.setCorsConfigurations(this.getCorsConfigurations());
            return handlerMapping;
        }
    }

    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
    }

    @Bean
    public ResourceUrlProvider mvcResourceUrlProvider() {
        ResourceUrlProvider urlProvider = new ResourceUrlProvider();
        urlProvider.setUrlPathHelper(this.getPathMatchConfigurer().getUrlPathHelperOrDefault());
        urlProvider.setPathMatcher(this.getPathMatchConfigurer().getPathMatcherOrDefault());
        return urlProvider;
    }

    @Bean
    @Nullable
    public HandlerMapping defaultServletHandlerMapping() {
        Assert.state(this.servletContext != null, "No ServletContext set");
        DefaultServletHandlerConfigurer configurer = new DefaultServletHandlerConfigurer(this.servletContext);
        this.configureDefaultServletHandling(configurer);
        return configurer.buildHandlerMapping();
    }

    protected void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
    }

    @Bean
    public RequestMappingHandlerAdapter requestMappingHandlerAdapter(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager, @Qualifier("mvcConversionService") FormattingConversionService conversionService, @Qualifier("mvcValidator") Validator validator) {
        RequestMappingHandlerAdapter adapter = this.createRequestMappingHandlerAdapter();
        adapter.setContentNegotiationManager(contentNegotiationManager);
        adapter.setMessageConverters(this.getMessageConverters());
        adapter.setWebBindingInitializer(this.getConfigurableWebBindingInitializer(conversionService, validator));
        adapter.setCustomArgumentResolvers(this.getArgumentResolvers());
        adapter.setCustomReturnValueHandlers(this.getReturnValueHandlers());
        if (jackson2Present) {
            adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
            adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
        }

        AsyncSupportConfigurer configurer = this.getAsyncSupportConfigurer();
        if (configurer.getTaskExecutor() != null) {
            adapter.setTaskExecutor(configurer.getTaskExecutor());
        }

        if (configurer.getTimeout() != null) {
            adapter.setAsyncRequestTimeout(configurer.getTimeout());
        }

        adapter.setCallableInterceptors(configurer.getCallableInterceptors());
        adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());
        return adapter;
    }

    protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {
        return new RequestMappingHandlerAdapter();
    }

    @Bean
    public HandlerFunctionAdapter handlerFunctionAdapter() {
        HandlerFunctionAdapter adapter = new HandlerFunctionAdapter();
        AsyncSupportConfigurer configurer = this.getAsyncSupportConfigurer();
        if (configurer.getTimeout() != null) {
            adapter.setAsyncRequestTimeout(configurer.getTimeout());
        }

        return adapter;
    }

    protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer(FormattingConversionService mvcConversionService, Validator mvcValidator) {
        ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
        initializer.setConversionService(mvcConversionService);
        initializer.setValidator(mvcValidator);
        MessageCodesResolver messageCodesResolver = this.getMessageCodesResolver();
        if (messageCodesResolver != null) {
            initializer.setMessageCodesResolver(messageCodesResolver);
        }

        return initializer;
    }

    @Nullable
    protected MessageCodesResolver getMessageCodesResolver() {
        return null;
    }

    @Bean
    public FormattingConversionService mvcConversionService() {
        FormattingConversionService conversionService = new DefaultFormattingConversionService();
        this.addFormatters(conversionService);
        return conversionService;
    }

    protected void addFormatters(FormatterRegistry registry) {
    }

    @Bean
    public Validator mvcValidator() {
        Validator validator = this.getValidator();
        if (validator == null) {
            if (ClassUtils.isPresent("javax.validation.Validator", this.getClass().getClassLoader())) {
                Class clazz;
                try {
                    String className = "org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean";
                    clazz = ClassUtils.forName(className, WebMvcConfigurationSupport.class.getClassLoader());
                } catch (LinkageError | ClassNotFoundException var4) {
                    throw new BeanInitializationException("Failed to resolve default validator class", var4);
                }

                validator = (Validator)BeanUtils.instantiateClass(clazz);
            } else {
                validator = new NoOpValidator();
            }
        }

        return (Validator)validator;
    }

    @Nullable
    protected Validator getValidator() {
        return null;
    }

    protected final List<HandlerMethodArgumentResolver> getArgumentResolvers() {
        if (this.argumentResolvers == null) {
            this.argumentResolvers = new ArrayList();
            this.addArgumentResolvers(this.argumentResolvers);
        }

        return this.argumentResolvers;
    }

    protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
    }

    protected final List<HandlerMethodReturnValueHandler> getReturnValueHandlers() {
        if (this.returnValueHandlers == null) {
            this.returnValueHandlers = new ArrayList();
            this.addReturnValueHandlers(this.returnValueHandlers);
        }

        return this.returnValueHandlers;
    }

    protected void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
    }

    protected final List<HttpMessageConverter<?>> getMessageConverters() {
        if (this.messageConverters == null) {
            this.messageConverters = new ArrayList();
            this.configureMessageConverters(this.messageConverters);
            if (this.messageConverters.isEmpty()) {
                this.addDefaultHttpMessageConverters(this.messageConverters);
            }

            this.extendMessageConverters(this.messageConverters);
        }

        return this.messageConverters;
    }

    protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    }

    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
    }

    protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
        messageConverters.add(new ByteArrayHttpMessageConverter());
        messageConverters.add(new StringHttpMessageConverter());
        messageConverters.add(new ResourceHttpMessageConverter());
        messageConverters.add(new ResourceRegionHttpMessageConverter());
        if (!shouldIgnoreXml) {
            try {
                messageConverters.add(new SourceHttpMessageConverter());
            } catch (Throwable var3) {
            }
        }

        messageConverters.add(new AllEncompassingFormHttpMessageConverter());
        if (romePresent) {
            messageConverters.add(new AtomFeedHttpMessageConverter());
            messageConverters.add(new RssChannelHttpMessageConverter());
        }

        Jackson2ObjectMapperBuilder builder;
        if (!shouldIgnoreXml) {
            if (jackson2XmlPresent) {
                builder = Jackson2ObjectMapperBuilder.xml();
                if (this.applicationContext != null) {
                    builder.applicationContext(this.applicationContext);
                }

                messageConverters.add(new MappingJackson2XmlHttpMessageConverter(builder.build()));
            } else if (jaxb2Present) {
                messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
            }
        }

        if (kotlinSerializationJsonPresent) {
            messageConverters.add(new KotlinSerializationJsonHttpMessageConverter());
        }

        if (jackson2Present) {
            builder = Jackson2ObjectMapperBuilder.json();
            if (this.applicationContext != null) {
                builder.applicationContext(this.applicationContext);
            }

            messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build()));
        } else if (gsonPresent) {
            messageConverters.add(new GsonHttpMessageConverter());
        } else if (jsonbPresent) {
            messageConverters.add(new JsonbHttpMessageConverter());
        }

        if (jackson2SmilePresent) {
            builder = Jackson2ObjectMapperBuilder.smile();
            if (this.applicationContext != null) {
                builder.applicationContext(this.applicationContext);
            }

            messageConverters.add(new MappingJackson2SmileHttpMessageConverter(builder.build()));
        }

        if (jackson2CborPresent) {
            builder = Jackson2ObjectMapperBuilder.cbor();
            if (this.applicationContext != null) {
                builder.applicationContext(this.applicationContext);
            }

            messageConverters.add(new MappingJackson2CborHttpMessageConverter(builder.build()));
        }

    }

    protected AsyncSupportConfigurer getAsyncSupportConfigurer() {
        if (this.asyncSupportConfigurer == null) {
            this.asyncSupportConfigurer = new AsyncSupportConfigurer();
            this.configureAsyncSupport(this.asyncSupportConfigurer);
        }

        return this.asyncSupportConfigurer;
    }

    protected void configureAsyncSupport(AsyncSupportConfigurer configurer) {
    }

    @Bean
    public CompositeUriComponentsContributor mvcUriComponentsContributor(@Qualifier("mvcConversionService") FormattingConversionService conversionService, @Qualifier("requestMappingHandlerAdapter") RequestMappingHandlerAdapter requestMappingHandlerAdapter) {
        return new CompositeUriComponentsContributor(requestMappingHandlerAdapter.getArgumentResolvers(), conversionService);
    }

    @Bean
    public HttpRequestHandlerAdapter httpRequestHandlerAdapter() {
        return new HttpRequestHandlerAdapter();
    }

    @Bean
    public SimpleControllerHandlerAdapter simpleControllerHandlerAdapter() {
        return new SimpleControllerHandlerAdapter();
    }

    @Bean
    public HandlerExceptionResolver handlerExceptionResolver(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager) {
        List<HandlerExceptionResolver> exceptionResolvers = new ArrayList();
        this.configureHandlerExceptionResolvers(exceptionResolvers);
        if (exceptionResolvers.isEmpty()) {
            this.addDefaultHandlerExceptionResolvers(exceptionResolvers, contentNegotiationManager);
        }

        this.extendHandlerExceptionResolvers(exceptionResolvers);
        HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();
        composite.setOrder(0);
        composite.setExceptionResolvers(exceptionResolvers);
        return composite;
    }

    protected void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
    }

    protected void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
    }

    protected final void addDefaultHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers, ContentNegotiationManager mvcContentNegotiationManager) {
        ExceptionHandlerExceptionResolver exceptionHandlerResolver = this.createExceptionHandlerExceptionResolver();
        exceptionHandlerResolver.setContentNegotiationManager(mvcContentNegotiationManager);
        exceptionHandlerResolver.setMessageConverters(this.getMessageConverters());
        exceptionHandlerResolver.setCustomArgumentResolvers(this.getArgumentResolvers());
        exceptionHandlerResolver.setCustomReturnValueHandlers(this.getReturnValueHandlers());
        if (jackson2Present) {
            exceptionHandlerResolver.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
        }

        if (this.applicationContext != null) {
            exceptionHandlerResolver.setApplicationContext(this.applicationContext);
        }

        exceptionHandlerResolver.afterPropertiesSet();
        exceptionResolvers.add(exceptionHandlerResolver);
        ResponseStatusExceptionResolver responseStatusResolver = new ResponseStatusExceptionResolver();
        responseStatusResolver.setMessageSource(this.applicationContext);
        exceptionResolvers.add(responseStatusResolver);
        exceptionResolvers.add(new DefaultHandlerExceptionResolver());
    }

    protected ExceptionHandlerExceptionResolver createExceptionHandlerExceptionResolver() {
        return new ExceptionHandlerExceptionResolver();
    }

    @Bean
    public ViewResolver mvcViewResolver(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager) {
        ViewResolverRegistry registry = new ViewResolverRegistry(contentNegotiationManager, this.applicationContext);
        this.configureViewResolvers(registry);
        if (registry.getViewResolvers().isEmpty() && this.applicationContext != null) {
            String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.applicationContext, ViewResolver.class, true, false);
            if (names.length == 1) {
                registry.getViewResolvers().add(new InternalResourceViewResolver());
            }
        }

        ViewResolverComposite composite = new ViewResolverComposite();
        composite.setOrder(registry.getOrder());
        composite.setViewResolvers(registry.getViewResolvers());
        if (this.applicationContext != null) {
            composite.setApplicationContext(this.applicationContext);
        }

        if (this.servletContext != null) {
            composite.setServletContext(this.servletContext);
        }

        return composite;
    }

    protected void configureViewResolvers(ViewResolverRegistry registry) {
    }

    protected final Map<String, CorsConfiguration> getCorsConfigurations() {
        if (this.corsConfigurations == null) {
            CorsRegistry registry = new CorsRegistry();
            this.addCorsMappings(registry);
            this.corsConfigurations = registry.getCorsConfigurations();
        }

        return this.corsConfigurations;
    }

    protected void addCorsMappings(CorsRegistry registry) {
    }

    @Bean
    @Lazy
    public HandlerMappingIntrospector mvcHandlerMappingIntrospector() {
        return new HandlerMappingIntrospector();
    }

    @Bean
    public LocaleResolver localeResolver() {
        return new AcceptHeaderLocaleResolver();
    }

    @Bean
    public ThemeResolver themeResolver() {
        return new FixedThemeResolver();
    }

    @Bean
    public FlashMapManager flashMapManager() {
        return new SessionFlashMapManager();
    }

    @Bean
    public RequestToViewNameTranslator viewNameTranslator() {
        return new DefaultRequestToViewNameTranslator();
    }

    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);
        kotlinSerializationJsonPresent = ClassUtils.isPresent("kotlinx.serialization.json.Json", classLoader);
    }

    private static final class NoOpValidator implements Validator {
        private NoOpValidator() {
        }

        public boolean supports(Class<?> clazz) {
            return false;
        }

        public void validate(@Nullable Object target, Errors errors) {
        }
    }
}

 

 

이것은 스프링 부트가 autoConfiguration을 해주는 클래스 중에  WebMvcAutoConfiguration을 보면 @ConditionalOnMissingBean({WebMvcConfigurationSupport.class}) 이 있는데

이미 WebMvcConfigurationSupport를 상속받아서 사용을 하게 되면 

스프링부트가 이미 빈으로 등록이 되어있기때문에 기본 전략을 사용하지 못한다.

 

@AutoConfiguration(
    after = {DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class}
)
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
public class WebMvcAutoConfiguration {
    public static final String DEFAULT_PREFIX = "";
    public static final String DEFAULT_SUFFIX = "";
    public static final PathPatternParser pathPatternParser = new PathPatternParser();
    private static final String SERVLET_LOCATION = "/";

    public WebMvcAutoConfiguration() {
    }

    @Bean
    @ConditionalOnMissingBean({HiddenHttpMethodFilter.class})
    @ConditionalOnProperty(
        prefix = "spring.mvc.hiddenmethod.filter",
        name = {"enabled"}
    )
    public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
        return new OrderedHiddenHttpMethodFilter();
    }

    @Bean
    @ConditionalOnMissingBean({FormContentFilter.class})
    @ConditionalOnProperty(
        prefix = "spring.mvc.formcontent.filter",
        name = {"enabled"},
        matchIfMissing = true
    )
    public OrderedFormContentFilter formContentFilter() {
        return new OrderedFormContentFilter();
    }

    static class OptionalPathExtensionContentNegotiationStrategy implements ContentNegotiationStrategy {
        private static final String SKIP_ATTRIBUTE = PathExtensionContentNegotiationStrategy.class.getName() + ".SKIP";
        private final ContentNegotiationStrategy delegate;

        OptionalPathExtensionContentNegotiationStrategy(ContentNegotiationStrategy delegate) {
            this.delegate = delegate;
        }

        public List<MediaType> resolveMediaTypes(NativeWebRequest webRequest) throws HttpMediaTypeNotAcceptableException {
            Object skip = webRequest.getAttribute(SKIP_ATTRIBUTE, 0);
            return skip != null && Boolean.parseBoolean(skip.toString()) ? MEDIA_TYPE_ALL_LIST : this.delegate.resolveMediaTypes(webRequest);
        }
    }

    static class ResourceChainResourceHandlerRegistrationCustomizer implements ResourceHandlerRegistrationCustomizer {
        private final WebProperties.Resources resourceProperties;

        ResourceChainResourceHandlerRegistrationCustomizer(WebProperties.Resources resourceProperties) {
            this.resourceProperties = resourceProperties;
        }

        public void customize(ResourceHandlerRegistration registration) {
            WebProperties.Resources.Chain properties = this.resourceProperties.getChain();
            this.configureResourceChain(properties, registration.resourceChain(properties.isCache()));
        }

        private void configureResourceChain(WebProperties.Resources.Chain properties, ResourceChainRegistration chain) {
            WebProperties.Resources.Chain.Strategy strategy = properties.getStrategy();
            if (properties.isCompressed()) {
                chain.addResolver(new EncodedResourceResolver());
            }

            if (strategy.getFixed().isEnabled() || strategy.getContent().isEnabled()) {
                chain.addResolver(this.getVersionResourceResolver(strategy));
            }

        }

        private ResourceResolver getVersionResourceResolver(WebProperties.Resources.Chain.Strategy properties) {
            VersionResourceResolver resolver = new VersionResourceResolver();
            if (properties.getFixed().isEnabled()) {
                String version = properties.getFixed().getVersion();
                String[] paths = properties.getFixed().getPaths();
                resolver.addFixedVersionStrategy(version, paths);
            }

            if (properties.getContent().isEnabled()) {
                String[] paths = properties.getContent().getPaths();
                resolver.addContentVersionStrategy(paths);
            }

            return resolver;
        }
    }

    interface ResourceHandlerRegistrationCustomizer {
        void customize(ResourceHandlerRegistration registration);
    }

    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnEnabledResourceChain
    static class ResourceChainCustomizerConfiguration {
        ResourceChainCustomizerConfiguration() {
        }

        @Bean
        ResourceChainResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer(WebProperties webProperties) {
            return new ResourceChainResourceHandlerRegistrationCustomizer(webProperties.getResources());
        }
    }

    @Configuration(
        proxyBeanMethods = false
    )
    @EnableConfigurationProperties({WebProperties.class})
    public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {
        private final WebProperties.Resources resourceProperties;
        private final WebMvcProperties mvcProperties;
        private final WebProperties webProperties;
        private final ListableBeanFactory beanFactory;
        private final WebMvcRegistrations mvcRegistrations;
        private ResourceLoader resourceLoader;

        public EnableWebMvcConfiguration(WebMvcProperties mvcProperties, WebProperties webProperties, ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider, ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider, ListableBeanFactory beanFactory) {
            this.resourceProperties = webProperties.getResources();
            this.mvcProperties = mvcProperties;
            this.webProperties = webProperties;
            this.mvcRegistrations = (WebMvcRegistrations)mvcRegistrationsProvider.getIfUnique();
            this.beanFactory = beanFactory;
        }

        @Bean
        public RequestMappingHandlerAdapter requestMappingHandlerAdapter(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager, @Qualifier("mvcConversionService") FormattingConversionService conversionService, @Qualifier("mvcValidator") Validator validator) {
            RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter(contentNegotiationManager, conversionService, validator);
            adapter.setIgnoreDefaultModelOnRedirect(this.mvcProperties == null || this.mvcProperties.isIgnoreDefaultModelOnRedirect());
            return adapter;
        }

        protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {
            if (this.mvcRegistrations != null) {
                RequestMappingHandlerAdapter adapter = this.mvcRegistrations.getRequestMappingHandlerAdapter();
                if (adapter != null) {
                    return adapter;
                }
            }

            return super.createRequestMappingHandlerAdapter();
        }

        @Bean
        public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext, FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
            WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(new TemplateAvailabilityProviders(applicationContext), applicationContext, this.getWelcomePage(), this.mvcProperties.getStaticPathPattern());
            welcomePageHandlerMapping.setInterceptors(this.getInterceptors(mvcConversionService, mvcResourceUrlProvider));
            welcomePageHandlerMapping.setCorsConfigurations(this.getCorsConfigurations());
            return welcomePageHandlerMapping;
        }

        @Bean
        @ConditionalOnMissingBean(
            name = {"localeResolver"}
        )
        public LocaleResolver localeResolver() {
            if (this.webProperties.getLocaleResolver() == org.springframework.boot.autoconfigure.web.WebProperties.LocaleResolver.FIXED) {
                return new FixedLocaleResolver(this.webProperties.getLocale());
            } else {
                AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
                localeResolver.setDefaultLocale(this.webProperties.getLocale());
                return localeResolver;
            }
        }

        @Bean
        @ConditionalOnMissingBean(
            name = {"themeResolver"}
        )
        public ThemeResolver themeResolver() {
            return super.themeResolver();
        }

        @Bean
        @ConditionalOnMissingBean(
            name = {"flashMapManager"}
        )
        public FlashMapManager flashMapManager() {
            return super.flashMapManager();
        }

        private Resource getWelcomePage() {
            String[] var1 = this.resourceProperties.getStaticLocations();
            int var2 = var1.length;

            for(int var3 = 0; var3 < var2; ++var3) {
                String location = var1[var3];
                Resource indexHtml = this.getIndexHtml(location);
                if (indexHtml != null) {
                    return indexHtml;
                }
            }

            ServletContext servletContext = this.getServletContext();
            if (servletContext != null) {
                return this.getIndexHtml((Resource)(new ServletContextResource(servletContext, "/")));
            } else {
                return null;
            }
        }

        private Resource getIndexHtml(String location) {
            return this.getIndexHtml(this.resourceLoader.getResource(location));
        }

        private Resource getIndexHtml(Resource location) {
            try {
                Resource resource = location.createRelative("index.html");
                if (resource.exists() && resource.getURL() != null) {
                    return resource;
                }
            } catch (Exception var3) {
            }

            return null;
        }

        @Bean
        public FormattingConversionService mvcConversionService() {
            WebMvcProperties.Format format = this.mvcProperties.getFormat();
            WebConversionService conversionService = new WebConversionService((new DateTimeFormatters()).dateFormat(format.getDate()).timeFormat(format.getTime()).dateTimeFormat(format.getDateTime()));
            this.addFormatters(conversionService);
            return conversionService;
        }

        @Bean
        public Validator mvcValidator() {
            return !ClassUtils.isPresent("javax.validation.Validator", this.getClass().getClassLoader()) ? super.mvcValidator() : ValidatorAdapter.get(this.getApplicationContext(), this.getValidator());
        }

        protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
            if (this.mvcRegistrations != null) {
                RequestMappingHandlerMapping mapping = this.mvcRegistrations.getRequestMappingHandlerMapping();
                if (mapping != null) {
                    return mapping;
                }
            }

            return super.createRequestMappingHandlerMapping();
        }

        protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer(FormattingConversionService mvcConversionService, Validator mvcValidator) {
            try {
                return (ConfigurableWebBindingInitializer)this.beanFactory.getBean(ConfigurableWebBindingInitializer.class);
            } catch (NoSuchBeanDefinitionException var4) {
                return super.getConfigurableWebBindingInitializer(mvcConversionService, mvcValidator);
            }
        }

        protected ExceptionHandlerExceptionResolver createExceptionHandlerExceptionResolver() {
            if (this.mvcRegistrations != null) {
                ExceptionHandlerExceptionResolver resolver = this.mvcRegistrations.getExceptionHandlerExceptionResolver();
                if (resolver != null) {
                    return resolver;
                }
            }

            return super.createExceptionHandlerExceptionResolver();
        }

        protected void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
            super.extendHandlerExceptionResolvers(exceptionResolvers);
            if (this.mvcProperties.isLogResolvedException()) {
                Iterator var2 = exceptionResolvers.iterator();

                while(var2.hasNext()) {
                    HandlerExceptionResolver resolver = (HandlerExceptionResolver)var2.next();
                    if (resolver instanceof AbstractHandlerExceptionResolver) {
                        ((AbstractHandlerExceptionResolver)resolver).setWarnLogCategory(resolver.getClass().getName());
                    }
                }
            }

        }

        @Bean
        public ContentNegotiationManager mvcContentNegotiationManager() {
            ContentNegotiationManager manager = super.mvcContentNegotiationManager();
            List<ContentNegotiationStrategy> strategies = manager.getStrategies();
            ListIterator<ContentNegotiationStrategy> iterator = strategies.listIterator();

            while(iterator.hasNext()) {
                ContentNegotiationStrategy strategy = (ContentNegotiationStrategy)iterator.next();
                if (strategy instanceof PathExtensionContentNegotiationStrategy) {
                    iterator.set(new OptionalPathExtensionContentNegotiationStrategy(strategy));
                }
            }

            return manager;
        }

        public void setResourceLoader(ResourceLoader resourceLoader) {
            this.resourceLoader = resourceLoader;
        }
    }

    @Configuration(
        proxyBeanMethods = false
    )
    @Import({EnableWebMvcConfiguration.class})
    @EnableConfigurationProperties({WebMvcProperties.class, WebProperties.class})
    @Order(0)
    public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware {
        private static final Log logger = LogFactory.getLog(WebMvcConfigurer.class);
        private final WebProperties.Resources resourceProperties;
        private final WebMvcProperties mvcProperties;
        private final ListableBeanFactory beanFactory;
        private final ObjectProvider<HttpMessageConverters> messageConvertersProvider;
        private final ObjectProvider<DispatcherServletPath> dispatcherServletPath;
        private final ObjectProvider<ServletRegistrationBean<?>> servletRegistrations;
        private final ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;
        private ServletContext servletContext;

        public WebMvcAutoConfigurationAdapter(WebProperties webProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider, ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider, ObjectProvider<DispatcherServletPath> dispatcherServletPath, ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) {
            this.resourceProperties = webProperties.getResources();
            this.mvcProperties = mvcProperties;
            this.beanFactory = beanFactory;
            this.messageConvertersProvider = messageConvertersProvider;
            this.resourceHandlerRegistrationCustomizer = (ResourceHandlerRegistrationCustomizer)resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
            this.dispatcherServletPath = dispatcherServletPath;
            this.servletRegistrations = servletRegistrations;
            this.mvcProperties.checkConfiguration();
        }

        public void setServletContext(ServletContext servletContext) {
            this.servletContext = servletContext;
        }

        public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
            this.messageConvertersProvider.ifAvailable((customConverters) -> {
                converters.addAll(customConverters.getConverters());
            });
        }

        public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
            if (this.beanFactory.containsBean("applicationTaskExecutor")) {
                Object taskExecutor = this.beanFactory.getBean("applicationTaskExecutor");
                if (taskExecutor instanceof AsyncTaskExecutor) {
                    configurer.setTaskExecutor((AsyncTaskExecutor)taskExecutor);
                }
            }

            Duration timeout = this.mvcProperties.getAsync().getRequestTimeout();
            if (timeout != null) {
                configurer.setDefaultTimeout(timeout.toMillis());
            }

        }

        public void configurePathMatch(PathMatchConfigurer configurer) {
            if (this.mvcProperties.getPathmatch().getMatchingStrategy() == MatchingStrategy.PATH_PATTERN_PARSER) {
                configurer.setPatternParser(WebMvcAutoConfiguration.pathPatternParser);
            }

            configurer.setUseSuffixPatternMatch(this.mvcProperties.getPathmatch().isUseSuffixPattern());
            configurer.setUseRegisteredSuffixPatternMatch(this.mvcProperties.getPathmatch().isUseRegisteredSuffixPattern());
            this.dispatcherServletPath.ifAvailable((dispatcherPath) -> {
                String servletUrlMapping = dispatcherPath.getServletUrlMapping();
                if (servletUrlMapping.equals("/") && this.singleDispatcherServlet()) {
                    UrlPathHelper urlPathHelper = new UrlPathHelper();
                    urlPathHelper.setAlwaysUseFullPath(true);
                    configurer.setUrlPathHelper(urlPathHelper);
                }

            });
        }

        private boolean singleDispatcherServlet() {
            Stream var10000 = this.servletRegistrations.stream().map(ServletRegistrationBean::getServlet);
            DispatcherServlet.class.getClass();
            return var10000.filter(DispatcherServlet.class::isInstance).count() == 1L;
        }

        public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
            WebMvcProperties.Contentnegotiation contentnegotiation = this.mvcProperties.getContentnegotiation();
            configurer.favorPathExtension(contentnegotiation.isFavorPathExtension());
            configurer.favorParameter(contentnegotiation.isFavorParameter());
            if (contentnegotiation.getParameterName() != null) {
                configurer.parameterName(contentnegotiation.getParameterName());
            }

            Map<String, MediaType> mediaTypes = this.mvcProperties.getContentnegotiation().getMediaTypes();
            mediaTypes.forEach(configurer::mediaType);
        }

        @Bean
        @ConditionalOnMissingBean
        public InternalResourceViewResolver defaultViewResolver() {
            InternalResourceViewResolver resolver = new InternalResourceViewResolver();
            resolver.setPrefix(this.mvcProperties.getView().getPrefix());
            resolver.setSuffix(this.mvcProperties.getView().getSuffix());
            return resolver;
        }

        @Bean
        @ConditionalOnBean({View.class})
        @ConditionalOnMissingBean
        public BeanNameViewResolver beanNameViewResolver() {
            BeanNameViewResolver resolver = new BeanNameViewResolver();
            resolver.setOrder(2147483637);
            return resolver;
        }

        @Bean
        @ConditionalOnBean({ViewResolver.class})
        @ConditionalOnMissingBean(
            name = {"viewResolver"},
            value = {ContentNegotiatingViewResolver.class}
        )
        public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
            ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
            resolver.setContentNegotiationManager((ContentNegotiationManager)beanFactory.getBean(ContentNegotiationManager.class));
            resolver.setOrder(Integer.MIN_VALUE);
            return resolver;
        }

        public MessageCodesResolver getMessageCodesResolver() {
            if (this.mvcProperties.getMessageCodesResolverFormat() != null) {
                DefaultMessageCodesResolver resolver = new DefaultMessageCodesResolver();
                resolver.setMessageCodeFormatter(this.mvcProperties.getMessageCodesResolverFormat());
                return resolver;
            } else {
                return null;
            }
        }

        public void addFormatters(FormatterRegistry registry) {
            ApplicationConversionService.addBeans(registry, this.beanFactory);
        }

        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            if (!this.resourceProperties.isAddMappings()) {
                logger.debug("Default resource handling disabled");
            } else {
                this.addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
                this.addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
                    registration.addResourceLocations(this.resourceProperties.getStaticLocations());
                    if (this.servletContext != null) {
                        ServletContextResource resource = new ServletContextResource(this.servletContext, "/");
                        registration.addResourceLocations(new Resource[]{resource});
                    }

                });
            }
        }

        private void addResourceHandler(ResourceHandlerRegistry registry, String pattern, String... locations) {
            this.addResourceHandler(registry, pattern, (registration) -> {
                registration.addResourceLocations(locations);
            });
        }

        private void addResourceHandler(ResourceHandlerRegistry registry, String pattern, Consumer<ResourceHandlerRegistration> customizer) {
            if (!registry.hasMappingForPattern(pattern)) {
                ResourceHandlerRegistration registration = registry.addResourceHandler(new String[]{pattern});
                customizer.accept(registration);
                registration.setCachePeriod(this.getSeconds(this.resourceProperties.getCache().getPeriod()));
                registration.setCacheControl(this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl());
                registration.setUseLastModified(this.resourceProperties.getCache().isUseLastModified());
                this.customizeResourceHandlerRegistration(registration);
            }
        }

        private Integer getSeconds(Duration cachePeriod) {
            return cachePeriod != null ? (int)cachePeriod.getSeconds() : null;
        }

        private void customizeResourceHandlerRegistration(ResourceHandlerRegistration registration) {
            if (this.resourceHandlerRegistrationCustomizer != null) {
                this.resourceHandlerRegistrationCustomizer.customize(registration);
            }

        }

        @Bean
        @ConditionalOnMissingBean({RequestContextListener.class, RequestContextFilter.class})
        @ConditionalOnMissingFilterBean({RequestContextFilter.class})
        public static RequestContextFilter requestContextFilter() {
            return new OrderedRequestContextFilter();
        }
    }
}

그런데 위에서 거론했던 @EnableWebMvc를 스프링 MVC 구성을 위한 클래스에 선언하면 WebMvcConfigurationSupport을 불러와 스프링 MVC를 구성한다.

-> @EnableWebMvc이것은 스프링부트의 자동설정과는 별게 이다. 아무튼 근데 자동구성을 해주긴한다.

 

이 과정에서 WebMvcConfigurationSupport가 컴포넌트로 등록되면서  @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) 조건을 만족시키지 못하게 되어 WebMvcAutoConfiguration은 비활성화 된다.

이와 유사하게 WebMvcConfigurationSupport를 확장한 클래스에 @Configuration를 선언하면 동일하게 적용된다.

 

 

결론

(@EnableWebMvc)WebMvcConfigurationSupport을 상속하거나 타입의 빈이 있으면 스프링부트의 WEBmvc자동구성에서 제외.

@EnableWebMvc과 스프링부트의 WebMvcAutoConfiguration의 등록되는 빈의 종류가 한 두개가 덜 등록됨.

뭐였더라... 나중에 작성을 해보자.

암튼 약간의 차이가 있지만 API를 구성하는데에는 지장이 없다.