springboot自定义配置与自动配置共存

springboot自定义配置与自动配置共存

springboot提供了大量的自动配置类,对于springmvc而言,通过配置application.yml设置一些参数就可以实现比较自适应的配置了。如果需要详细配置,就必须了解如何在springboot的环境下添加自己的配置、并选择是否仍然使用springboot的自动配置项。

主要配置类和注解

springmvc的一切配置源于配置类WebMvcConfigurationSupport,该类实现了ApplicationContextAwareServletContextAware这两个接口,即同时注入了spring上下文和servlet上下文。具体可以参考类注释。

注解@EnableWebMvc导入了这个配置类:

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

DelegatingWebMvcConfigurationWebMvcConfigurationSupport的子类:

@Configuration
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);
		}
	}
  
  // ...
}
复制代码

该类实现了多个WebMvcConfigurer的配置,通过添加Autowired注解在setConfigurers方法上,注入了系统中启用到的所有WebMvcConfigurer组件,然后按序执行每个实例的配置方法。其顺序由spring容器注入时决定,注解@Order可以影响到注入时目标组件的顺序,比如WebMvcAutoConfiguration中的静态内部类WebMvcAutoConfigurationAdapter就标注了@Order(0),表示该组件排在列表的首位。

springboot的mvc自动配置

@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
		ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration { ... }
复制代码

通过标注上的三个@Conditional注解,该类实现了web环境中的自动配置。

WebMvcAutoConfigurationAdapter是其静态内部类,该类真正提供了springboot mvc自动配置的能力,通过引入的ResourcePropertiesWebMvcProperties两个属性配置类,该类能够根据application.yml中定义的各种springmvc配置来实现自定义自动配置。

比如该类下的configureMessageConverters方法:

		@Override
		public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
			this.messageConvertersProvider.ifAvailable((customConverters) -> converters
					.addAll(customConverters.getConverters()));
		}
复制代码

该类默认导入了多个根据HTTP媒体类型来区分的消息转换器,根据具体的媒体类型来确定选择哪一个与之匹配的转换器。

如何添加自定义的配置

添加自定义消息转换器

默认的消息转换器中包含了Jackson的转换器:MappingJackson2HttpMessageConverter,但是该类无法实现日期格式的通用转换(通常使用的日期字符串格式为yyyy-MM-dd HH:mm:ss,但是Jackson无论是对Date还是LocalDateTime都没有使用到这一种格式),所以就必须使用自定义的WebMvcConfigurer,然后覆盖configureMessageConverters方法,添加上自己的配置:

/**
 * @author Gmw
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addSerializer(Date.class, new JsonSerializer<Date>() {
            @Override
            public void serialize(Date value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                gen.writeString(formatter.format(value));
            }
        });
        javaTimeModule.addDeserializer(Date.class, new JsonDeserializer<Date>() {
            @Override
            public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
                String value = p.getText();
                SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                try {
                    return formatter.parse(value);
                } catch (ParseException e) {
                    throw ExceptionAdvice.error("日期格式错误,要求格式:yyyy-MM-dd HH:mm:ss");
                }
            }
        });
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(javaTimeModule);

        // 未使用EnableWebMvc注解,清空掉springboot自动配置的一大串默认转换器
        converters.clear();
        converters.add(new MappingJackson2HttpMessageConverter(objectMapper));
    }
}
复制代码

要注意的是,该配置类未标注@EnableWebMvc注解,所以springboot的mvc自动配置类也会生效。

注意这一段代码:

// 未使用EnableWebMvc注解,清空掉springboot自动配置的一大串默认转换器
converters.clear();
converters.add(new MappingJackson2HttpMessageConverter(objectMapper));
复制代码

因为在DelegatingWebMvcConfiguration中,添加转换器的实现如下:

	private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
	@Override
	protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
		this.configurers.configureMessageConverters(converters);
	}
复制代码

WebMvcConfigurerComposite中的实现如下:

	@Override
	public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
		for (WebMvcConfigurer delegate : this.delegates) {
			delegate.configureMessageConverters(converters);
		}
	}
复制代码

每一个WebMvcConfigurer配置组件的操作都是对传入的入参converters进行增减操作。而springboot提供的自动配置类被标注为@Order(0),即在执行到我们自己写的方法中时,入参的converters已经具有了默认提供的多种转换器,如果不清理到这些默认转换器,就不能保证我们自己添加的转换器生效,具体代码参考:

  • 负责处理请求体反序列化为对象的AbstractMessageConverterMethodArgumentResolver
  • 负责处理响应体序列化的AbstractMessageConverterMethodProcessor

添加其他配置

覆盖WebMvcConfigurer提供的方法即可实现其他配置比如添加视图处理器、静态资源处理器、CORS跨域处理器等等。

原创文章,作者:睿达君,如若转载,请注明出处:https://zrrd.net.cn/2164.html

发表回复

登录后才能评论
咨询电话
联系电话:0451-81320577

地址:哈尔滨市松北区中小企业总部基地13F

微信咨询
微信咨询
QQ咨询
分享本页
返回顶部