如何覆盖Spring Boot RequestMappingHandlerMapping?

时间:2020-01-19 08:32:19

标签: java spring spring-boot spring-mvc

我通过向其添加一些功能来扩展RequestMappingHandlerMapping类

当我添加如下配置时:

@Configuration
public class MyConfig  extends DelegatingWebMvcConfiguration {

    @Override
    @Bean
    @Primary
    public RequestMappingHandlerMapping requestMappingHandlerMapping() {
        return super.requestMappingHandlerMapping();
    }

    @Override
    protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {

        //Here I create my new version RequestMappingHandlerMapping 
        return new MyNewVersionRequestMappingHandlerMapping();

    }

}

public class MyNewVersionRequestMappingHandlerMapping extends RequestMappingHandlerMapping {

    @Override
    protected RequestCondition<?> getCustomTypeCondition(final Class<?> handlerType) {
       // instead of null return my new Condition
       return new SomeCustomTypeCondition(handlerType);
    }

    @Override
    protected RequestCondition<?> getCustomMethodCondition(final Method method) {
       // instead of null return my new Condition
       return new SomeCustomTypeCondition(handlerType);
    }
}

然后启动应用程序,它显示:

The bean 'requestMappingHandlerMapping', defined in class path resource [com/test/MyConfig.class], 
could not be registered. A bean with that name has already been defined in class path resource 
[org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]
 and overriding is disabled.

WebMvcAutoConfiguration.EnableWebMvcConfiguration具有@Configuration批注,并从DelegatingWebMvcConfiguration扩展而来:

public class WebMvcAutoConfiguration {

...
    @Configuration
    public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {
...
       @Bean
       @Primary
       @Override
       public RequestMappingHandlerMapping requestMappingHandlerMapping() {
            // I want return my version of RequestMappingHandlerMapping, but how?
            return super.requestMappingHandlerMapping();
       }

... 

spring-boot-autoconfigure-2.1.9.RELEASE.jar中的使用链为:

-> META-INF\spring.factories 
  -> WebMvcAutoConfiguration 
    -> EnableWebMvcConfiguration 
      -> DelegatingWebMvcConfiguration. 

因此,当使用Spring Boot自动配置时,它被编码为使用DelegatingWebMvcConfiguration,我可以用我自己的版本替换这个默认值吗?

有时候我可以将选项添加到application.yml

  main:
    allow-bean-definition-overriding: true

有效。但我想避免这样做,因为此选项将隐藏Bean复制警告。

问题是:如何在不添加此类选项的情况下进行修复?

1 个答案:

答案 0 :(得分:1)

我可以使其与以下代码一起使用。希望问题能为您解决。

package com.jjs.in.config;



@Configuration
public class WebConfigMapping extends DelegatingWebMvcConfiguration{


//    @Configuration
//    public static class UnconditionalWebMvcAutoConfiguration implements WebMvcConfigurer { // extends WebMvcAutoConfiguration {//forces @EnableWebMvc
//    }

    @Override
    protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
        return new MyWebConfig.InternalPathRequestMappingHandlerMapping();
    }

    @Bean//("CASPER_REQUESTING_MAPPING")
    @Primary
    @Override
    public RequestMappingHandlerMapping requestMappingHandlerMapping(
            @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
            @Qualifier("mvcConversionService") FormattingConversionService conversionService,
            @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
        return super.requestMappingHandlerMapping(contentNegotiationManager, conversionService,resourceUrlProvider);
    }

}

@Slf4j
@Configuration
public class MyWebConfig {

    public static class InternalPathRequestMappingHandlerMapping extends RequestMappingHandlerMapping {

        @Override
        protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
            RequestMappingInfo methodMapping = super.getMappingForMethod(method, handlerType);
            if (methodMapping == null)
                return null;

            List<String> superclassUrlPatterns = new ArrayList<>();

            for (Class<?> clazz = handlerType; clazz != Object.class; clazz = clazz.getSuperclass()) {
                    if (clazz.isAnnotationPresent(InternalRequest.class))
                            superclassUrlPatterns.add((String)methodMapping.getPatternsCondition().getPatterns().toArray()[0]);

            }
            if (method.isAnnotationPresent(InternalRequest.class) && superclassUrlPatterns.isEmpty()){
                superclassUrlPatterns.add((String)methodMapping.getPatternsCondition().getPatterns().toArray()[0]);
            }
            if (!superclassUrlPatterns.isEmpty()) {
                String newUrl = "MY_PREFIX"+ superclassUrlPatterns.get(0);
                RequestMappingInfo superclassRequestMappingInfo = new RequestMappingInfo(methodMapping.getName(),
                        new PatternsRequestCondition(newUrl), methodMapping.getMethodsCondition()
                        , methodMapping.getParamsCondition()
                        , methodMapping.getHeadersCondition()
                        , methodMapping.getConsumesCondition()
                        , methodMapping.getProducesCondition()
                        , methodMapping.getCustomCondition());

                return superclassRequestMappingInfo;
            } else {
                return methodMapping;
            }
        }

    }
}