spring boot(二)自动装配原理 - 实例分析(HttpEncodingAutoConfiguration)

在了解了Spring Boot的运作原理后,现在来简单的分析一个Spring Boot内置的自动配置功能:http的编码配置。
我们在常规项目中配置Http编码的时候是在web.xml添加一个filter,如:

<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
 <filter-mapping>
      <filter-name>encodingFilter</filter-name>
      <url-pattern>/*</url-pattern>
  </filter-mapping>

spring boot要完成自动配置,就要满足两个条件:

  1. 能配置CharacterEncodingFilter这个Bean;
  2. 能配置encoding和forceEncoding两个参数。

1.自动配置

我们在org.springframework.boot.autoconfigure.web.servlet包中找到HttpEncodingAutoConfiguration类后,可以看到源码如下:

@Configuration
@EnableConfigurationProperties(HttpProperties.class)
// Spring 底层 @Conditional 注解,根据不同的条件,如果满足指定的条件,整个配置类里面的配置就会生效,该注解是判断当前应用是否是web应用,如果是, HttpEncodingAutoConfiguration 配置类生效;
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
// 判断当前项目有没有这个类 CharacterEncodingFilter;SpringMVC 中进行乱码解决的过滤器,如果有则 HttpEncodingAutoConfiguration 配置生效;
@ConditionalOnClass(CharacterEncodingFilter.class)
// 判断 application.properties 配置文件中是否存在 spring.http.encoding.enabled,如果不存在,判断也是成立的,因为 matchIfMissing=true,即缺省时默认为 true。
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {

	private final HttpProperties.Encoding properties;

	public HttpEncodingAutoConfiguration(HttpProperties properties) {
		this.properties = properties.getEncoding();
	}

	@Bean // 使用java方式配置CharacterEncodingFilter的Bean
	@ConditionalOnMissingBean // spring容器中没有这个类时
	public CharacterEncodingFilter characterEncodingFilter() {
		CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
		filter.setEncoding(this.properties.getCharset().name());
		filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
		filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
		return filter;
	}

	@Bean
	public LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
		return new LocaleCharsetMappingsCustomizer(this.properties);
	}

	private static class LocaleCharsetMappingsCustomizer implements
			WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {

		private final HttpProperties.Encoding properties;

		LocaleCharsetMappingsCustomizer(HttpProperties.Encoding properties) {
			this.properties = properties;
		}

		@Override
		public void customize(ConfigurableServletWebServerFactory factory) {
			if (this.properties.getMapping() != null) {
				factory.setLocaleCharsetMappings(this.properties.getMapping());
			}
		}

		@Override
		public int getOrder() {
			return 0;
		}

	}
}

可以看到这个类上总共有5个注解,我们分别来看这些注解的作用。

1.1@Configuration

@Configuration:表示这个类是一个配置类,并将这个类加入IOC容器。

1.2@EnableConfigurationProperties

@EnableConfigurationProperties(HttpProperties.class):启动指定类的ConfigurationProperties功能;将配置文件中对应的值和HttpEncodingProperties绑定起来;并把HttpEncodingProperties加入到ioc容器中。
进入这个注解,源码如下:

// 在application.properties使用prefix+属性名的方式可以修改默认配置
@ConfigurationProperties(prefix = "spring.http")
public class HttpProperties {

   private boolean logRequestDetails;

   private final Encoding encoding = new Encoding();

   public boolean isLogRequestDetails() {
      return this.logRequestDetails;
   }

   public void setLogRequestDetails(boolean logRequestDetails) {
      this.logRequestDetails = logRequestDetails;
   }

   public Encoding getEncoding() {
      return this.encoding;
   }

   public static class Encoding {

	  // spring boot默认的编码格式就是UTF-8
      public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;

      private Charset charset = DEFAULT_CHARSET;

      private Boolean force;

      private Boolean forceRequest;

      private Boolean forceResponse;

      private Map<Locale, Charset> mapping;

      public Charset getCharset() {
         return this.charset;
      }

      public void setCharset(Charset charset) {
         this.charset = charset;
      }

      public boolean isForce() {
         return Boolean.TRUE.equals(this.force);
      }

      public void setForce(boolean force) {
         this.force = force;
      }

      public boolean isForceRequest() {
         return Boolean.TRUE.equals(this.forceRequest);
      }

      public void setForceRequest(boolean forceRequest) {
         this.forceRequest = forceRequest;
      }

      public boolean isForceResponse() {
         return Boolean.TRUE.equals(this.forceResponse);
      }

      public void setForceResponse(boolean forceResponse) {
         this.forceResponse = forceResponse;
      }

      public Map<Locale, Charset> getMapping() {
         return this.mapping;
      }

      public void setMapping(Map<Locale, Charset> mapping) {
         this.mapping = mapping;
      }

      public boolean shouldForce(Type type) {
         Boolean force = (type != Type.REQUEST) ? this.forceResponse
               : this.forceRequest;
         if (force == null) {
            force = this.force;
         }
         if (force == null) {
            force = (type == Type.REQUEST);
         }
         return force;
      }

      public enum Type {

         REQUEST, RESPONSE

      }

   }

}

前面有说到spring boot的理念是“约定大于配置”,可如果我们想修改默认配置改怎么修改呢?我们只需要在application.properties配置文件中,按照prefix + 属性名,就可以修改对应的属性。在本例中,我们如果想修改项目的默认编码为GBK,只需要在全局配置文件中添加一行代码即可,代码如下:

spring.http.encoding.charset=GBK

通过上面的分析,我们知道了在配置文件中修改默认配置的原理。关于配置文件可配置属性,可以参考官方文档。

1.3Conditional

剩下的三个注解都是ConditionalOnXXX类型的注解,这类注解都是@Conditional注解的派生注解,作用是必须是@Conditional指定的条件成立,才给容器中添加组件,配置里的内容才会生效。
针对本例来说,必须@ConditionalOnWebApplication、@ConditionalOnClass、@ConditionalOnProperty三个注解对应的条件都生效,HttpEncodingAutoConfiguration配置类才会生效。

1.4快速查看当前生效的配置类

在spring.factories文件中,我们可以看到有上百个默认配置,如果我们想知道当前有哪些默认配置生效了,哪些没有生效,这样一个个去分析明显是不现实的。我们可以在application.properties配置文件中添加以下配置,来快速查看当前生效的默认配置:

debug=true

此时再启动应用时,就可以在控制台看到生效的配置与没有生效的配置,并且可以看到配置没有生效的原因。

Positive matches(生效的配置):
-----------------
		HttpEncodingAutoConfiguration matched:
      - @ConditionalOnClass found required class 'org.springframework.web.filter.CharacterEncodingFilter' (OnClassCondition)
      - found 'session' scope (OnWebApplicationCondition)
      - @ConditionalOnProperty (spring.http.encoding.enabled) matched (OnPropertyCondition)

   		HttpEncodingAutoConfiguration#characterEncodingFilter matched:
      - @ConditionalOnMissingBean (types: org.springframework.web.filter.CharacterEncodingFilter; SearchStrategy: all) did not find any beans (OnBeanCondition)
...

Negative matches(没有生效的配置):
-----------------
		ActiveMQAutoConfiguration:
      	Did not match:
         - @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition)

2.@Conditional扩展注解

除了以上解析到的注解,SpringBoot 还为我们提供了更多的有关 @Conditional 的派生注解。它们的作用:必须是 @Conditional 指定的条件成立,才给容器中添加组件,配置配里面的所有内容才生效:
在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值