Spring boot项目中排除自动配置类失败问题始末

20 篇文章 0 订阅
20 篇文章 0 订阅

正常情况下,在Spring boot项目中,对于多个自动配置类冲突问题,使用@EnableAutoConfiguration的exclude即可。

如下,存在两个配置类构造同一dataSource:

1.某包下DruidDataSourceAutoConfigSelf配置类(使用spring.factories进行的自动配置

package com.example.framework.autoconfigure.druid;

@Configuration

@ConditionalOnClass(DruidDataSource.class)

@AutoConfigureBefore({DataSourceAutoConfiguration.class, DruidDataSourceAutoConfigure.class})

@EnableConfigurationProperties({DruidStatProperties.class, DataSourceProperties.class})

@Import({DruidSpringAopConfiguration.class,

    DruidStatViewServletConfiguration.class,

    DruidWebStatFilterConfiguration.class,

    DruidFilterConfiguration.class})

@Slf4j

public class DruidDataSourceAutoConfigSelf {

  @Bean(initMethod = "init")

  public DruidDataSource dataSource(Environment env) {

    log.info("Init DruidDataSource");

    return DruidDataSourceBuilder

        .create()

        .build(env, "example.patch.druid.");

  }

}

2.某包下CollectorDataSourceConfig配置类(使用了主类上的@ComponentScan扫描

package com.example.common.config.datasource;

@Configuration

@Slf4j

@ConditionalOnProperty(name = "enable.collector", havingValue = "true", matchIfMissing = true)

@EnableAutoConfiguration

public class CollectorDataSourceConfig {

    ......

  @Bean(name = "collectorDatasource", initMethod = "init", destroyMethod = "close")

  public DataSource collectorDatasource() throws Exception {

    DruidDataSource collectorDatasource = new DruidDataSource();

    ...

    return collectorDatasource;

  }

  ......

}

由于均未做MissingCondition设置,因此启动会有问题,这时仅需保留需要的即可,例如想要保留CollectorDataSourceConfig。

那,仅需按如下方式即可(DruidDataSourceAutoConfigSelf为想要移除的配置类):

@SpringBootApplication(exclude = {DruidDataSourceAutoConfigSelf.class})

@ComponentScan({"com.example"})

public class Application {

  public static void main(String[] args){

    SpringApplication.run(Application.class, args);

  }

}

但是启动后,仍然报错,仔细观察,发现主类上存在:@ComponentScan({"com.example"})。且恰好该扫描范围囊括了上面两个配置类。有人会说,我已经排除了,为什么还会生效?由此引出本文第一个知识点:Spring Boot和Spring的机制“冲突”。

可以看到,@SpringBootApplication(exclude = {DruidDataSourceAutoConfigSelf.class})是Spring boot中的注解,而且使用了约定大于配置的“机制”(不是思想,因为这确实是一种机制)。但是,需要注意的是,他的机制是建立在Spring之上,作为”增强“而存在的,也就是他不会覆盖原来的Spring扫描机制。

所以,细心的同学可以看到,主类上的@ComponentScan({"com.example"})正好覆盖了两个配置,所以,仅仅将spring boot机制下的的自动配置排除仍不算,Spring还是会引入。

解决了这个问题后,再次启动,发现确实不加载DruidDataSourceAutoConfigSelf(注意仅仅是先),而且还是会报同样的错,难道还有别的@ComponentScan?仔细找了一圈,没有发现,很奇怪了,继续跟代码吧。

(思路:想要排查这个问题,只能看这个类到底是被谁引入了,好在Spring有记录)

跟到配置类集合处(该map中存储了所有的配置类信息),如下:

纠结的是,我发现这个类竟然是被他的竞争对手:CollectorDataSourceConfig引入的!!!

那回到CollectorDataSourceConfig类中去看吧,果然,有一点很可疑:配置了注解@EnableAutoConfiguration(这个注解就是开头我们看到的@SpringBootApplication(exclude = {DruidDataSourceAutoConfigSelf.class}))中使用的springboot的注解,详情如下:

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@SpringBootConfiguration

@EnableAutoConfiguration

@ComponentScan(excludeFilters = {

        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),

        @Filter(type = FilterType.CUSTOM,

                classes = AutoConfigurationExcludeFilter.class) })

public @interface SpringBootApplication {

    /**

     * Exclude specific auto-configuration classes such that they will never be applied.

     * @return the classes to exclude

     */

    @AliasFor(annotation = EnableAutoConfiguration.class, attribute = "exclude")

    Class<?>[] exclude() default {};

    ...

}

也就是说,费劲心机排除的设置,又被引入了。

讲到此,一目了然,说下结论吧:

  1. Spring boot自动配置和Spring的ComponentScan扫描会有“冲突”
  2. Spring boot中的注解@EnableAutoConfiguration除了主类上配置,其他地方不要填写
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值