首页 > 解决方案 > 在库中定义 Spring bean 并将它们从 ComponentScan 中排除

问题描述

我正在为两个应用程序 A 和 B 编写一个库。应用程序 A 使用 XML 定义 bean(没有组件扫描),而 B 使用注释和组件扫描。我想让库定义一些 A 和 B 都可以包含的 bean。但是,A 和 B 应该在它们在特定的 Spring 配置文件中启动时才包含这些 bean(比如说my_profile)。

TLDR 问题是:有没有一种方法可以在不引用my_profile库的情况下执行上述操作,并且不必从 B 的组件扫描中明确排除库?

目前,库中的 bean 被定义为 @Configuration 类中的 @Bean 方法,如下所示:

@Configuration
open class LibraryConfig {
  @Bean
  open fun libraryBean() = ...
}

现在在应用程序 A 中,在 XML 中,我可以这样做:

<beans profile="my_profile">
    <bean class="com.package.LibraryConfig" />
</beans>

那行得通。在使用注释的应用程序 B 中,我想做这样的事情:

@Configuration
@Profile("my_profile")
@Import(LibraryConfig::class)
open class MyProfileConfig

但是由于LibraryConfig也带有@Configuration注解,所以组件扫描总会找到。因此,这种使其有条件的方法不起作用。

我考虑过的方法:

  1. 只需将配置文件包含在 LibraryConfig 上的 @Profile 中。我不想这样做,因为图书馆不应该知道其消费者的个人资料。
  2. 从项目 B 的 @ComponentScan 中明确排除 LibraryConfig。这里的缺点是我们也有项目 CD 和 E,不会使用my_profile. 无论如何,我希望能够在其中包含该库,而不必明确排除其中的一部分。

所以我正在寻找一种方法来创建一个只能显式包含的“配置”类。或任何其他优雅的方式来完成上述操作。可以做到吗?

标签: springkotlin

解决方案


可能有一些方法可以将库包从项目 A 或 B 的组件扫描中排除,而无需明确说明要排除该包。

为您的库使用不同的包根
最直接的选择是为库使用与项目使用不同的包根。由于@SpringBootApplication注解是元注解的@ComponentScan,如果@ComponentScan的属性basePackageClassesbasePackages没有被指定,被注解的类的包名被用作根包,用于组件扫描(源代码)

配置组件扫描指令以与 @Configuration 类一起使用。提供与 Spring XML 的 context:component-scan 元素并行的支持。可以指定 basePackageClasses() 或 basePackages()(或其别名 value())来定义要扫描的特定包。如果未定义特定的包,则会从声明此注解的类的包中进行扫描。

例如,如果一个带@SpringBootApplication注释的根类位于 package com.example.somepackage


package com.example.somepackage;

@SpringBootApplication
public class DemoApplication {
    ...
}

基本包根com.example.somepackage将用作组件扫描的根。使用com.example.library而不是com.example.somepackage.library 应该将库排除在组件扫描中。

使用ConditionalOn库中的注解
如果上述方法不起作用,并且在组件扫描期间仍然自动包含配置,则与使用配置文件相比,侵入性稍低的方法是向@ConditionalOnX配置类添加注解,例如:

条件属性

@Configuration
@ConditionalOnProperty(prefix = "yourlibrary", name = "enabled", havingValue="true")

依赖该库的项目现在需要包含该属性yourlibrary.enabled=true

@ConditionalOn可以在此处找到有关多个注释的更多信息。


推荐阅读