Spring 与 Auto-Configuration

1. 简述

最近在捣鼓一个类似 Spring Boot starter 的小项目:把常见的 Web 开发所使用的组件或者技术方案封装在一起,通过一个 Maven 引用快速地将项目搭建起来。

2. 遇到的问题

遇到了一个问题:我在被引用项目中用 @Configuration 注解标注了一个类,在开发项目中这个类却没有被实例化。

该类代码如下所示:

  package com.avaloninc.web.aop.config;
  
  import com.avaloninc.web.aop.filter.RequestBodyWrapperFilter;
  import com.avaloninc.web.aop.interceptor.RequestAuditInterceptor;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.beans.factory.annotation.Value;
  import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  import org.springframework.context.annotation.Bean;
  import org.springframework.context.annotation.Configuration;
  import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
  import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
  
  /**
   * @Author: wuzhiyu.
   * @Date: 2019-02-22 15:15:18.
   * @Description:
   */
  @Configuration
  @ConditionalOnProperty(value = "log.request.audit.enable", havingValue = "true")
  public class RequestAuditConfiguration extends WebMvcConfigurerAdapter {
  
    private final String   logPartSeparator;
    private final String[] uriWhiteList;
  
    @Autowired
    public RequestAuditConfiguration(@Value("${log.request.audit.separator:'||'}") String logPartSeparator,
                                     @Value("${log.request.audit.whitelist:''}") String[] uriWhiteList) {
      this.logPartSeparator = logPartSeparator;
      this.uriWhiteList = uriWhiteList;
    }
  
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
      registry.addInterceptor(new RequestAuditInterceptor(logPartSeparator, uriWhiteList));
    }
  
    @Bean
    public RequestBodyWrapperFilter getRequestBodyWrapperFilter() {
      return new RequestBodyWrapperFilter();
    }
  }

3. 解决方案

定下心来想了一下,被引用项目的配置类全名为:com.avaloninc.web.aop.config.RequestAuditConfiguration ,而开发项目中以 @SpringBootApplication 修饰的启动类全名为 com.avaloninc.web.demo.Main

第一个想法是:会不会是因为包名的问题导致 Spring 没有去扫描 com.avaloninc.web.aop 包下面的 Bean 呢?

尝试了解决办法:在启动类上加上注解 @ComponentScan("com.avaloninc"),果然好使!

但是转念一想,Spring Boot 的各种 starter 中定义的 Bean 也不会和我们自己的项目同属于一个包下面啊,为什么它们没有这个问题呢?

于是找了一篇自定义 starter 的文章1看了看了一下。大部分没什么特别,但是其中提到了一个 spring.factories 文件唤醒了我记忆中关于 Spring Boot 初始化过程的一点记忆。所以果断在被引用项目中也加了这个文件 src/main/resources/META-INF/spring.factories,内容为:

  org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.avaloninc.web.aop.config.RequestAuditConfiguration

果然好使!

当然还是参考官方文档2来的更加详细准确。

4. 参考文献