从 Spring Boot 应用程序中排除 @Configuration

Posted

技术标签:

【中文标题】从 Spring Boot 应用程序中排除 @Configuration【英文标题】:Exclude @Configuration from Spring Boot Application 【发布时间】:2019-08-19 14:00:17 【问题描述】:

我有一堆模块(比如 3 个)。两个是基于 Spring Boot 的模块,另一个是基于 Spring 的。 说模块 1 - SpringBoot 模块 2 - Spring Boot 模块 3 - 仅基于 Spring 的通用模块

Module 3 @Configuration 定义的文件只需要Module 2 而不是Module 1 选择。

我尝试了很多方法来排除配置文件。例如:-

@SpringBootApplication
@ComponentScan(basePackages = "com.adobe"
, excludeFilters = 
    @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = WorkerConfig.class, WorkerExecutors.class, Worker.class))
public class Application 

  private static final Logger logger = LoggerFactory.getLogger(Application.class);

  public static void main(String[] args) throws Exception 
    SpringApplication.run(Application.class, args);
  


但是@Configiration 类仍然没有被排除,Spring 正在尝试将它加载到我不想要的应用程序上下文中。我的配置类

@Configuration
public class WorkerConfig 

  @Bean
  public WorkerExecutors workerExec() 
    WorkerExecutors executors = new WorkerExecutors();
    return executors;
  


我也确实在@ComponentScan 注释中读到了

 * <p>Note that the @code <context:component-scan> element has an
 * @code annotation-config attribute; however, this annotation does not. This is because
 * in almost all cases when using @code @ComponentScan, default annotation config
 * processing (e.g. processing @code @Autowired and friends) is assumed. Furthermore,
 * when using @link AnnotationConfigApplicationContext, annotation config processors are
 * always registered, meaning that any attempt to disable them at the
 * @code @ComponentScan level would be ignored.

所以看起来在组件扫描中排除是行不通的。除上述之外,我还尝试排除使用

@SpringBootApplication(exclude= WorkerExecutors.class, Worker.class,WorkerConfig.class)
public class Application 

但是弹簧靴会抛出

java.lang.IllegalStateException: The following classes could not be excluded because they are not auto-configuration classes:
    - com.adobe.repository.worker.lib.config.WorkerConfig
    - com.adobe.acp.repository.worker.lib.core.WorkerExecutors
    - com.adobe.acp.repository.worker.lib.core.Worker

知道如何禁用组件扫描弹簧引导模块中的非弹簧引导模块,而不是放入不同的包中。我不想放入不同的包装中。

感谢任何帮助!

【问题讨论】:

一种有点老套的方法是为Worker 配置提供@ConditionalOnProperty 注释,然后仅为模块2 设置属性。 是的,这行得通..我使用条件而不是属性条件,因为它带来了我想避免的 spring boot 依赖..但是你说它很hacky? 这有点骇人听闻,因为 - 正如在其他一些 cmets 中所提到的,您最好将模块拆分,以便只有需要在类路径上的代码实际上在类路径上(即模块 1 甚至不应该能够访问模块 3) 的不需要的配置类。通过像这样使用“分段”组件扫描,您可能会在路上遇到错误/问题,毕竟来自 Worker 确实的东西需要出现在模块 1 中,并迫使您重新设计这种方法.但是,如果它对您有用并且您可以处理这些问题,那么它也是一种方法。 同意这一点。但是现在它是一个单独的类,所以将它们移出类路径没有多大意义。但是,是的,当这样的事情增加时,代码肯定会变得错误且难以维护。 【参考方案1】:

你可以试试这个对我有用:

@SpringBootApplication
@ComponentScan(excludeFilters  = @ComponentScan.Filter(
              type = FilterType.ASSIGNABLE_TYPE, classes = WorkerConfig.class, WorkerExecutors.class, Worker.class))

【讨论】:

其实不会。 我发现只有在 @ComponentScan 注释上指定了 basePackages 属性时这才有效。【参考方案2】:

自动配置包位于 org.springframework.boot.autoconfigure 下。这就是你做不到的原因:

@SpringBootApplication(exclude= WorkerExecutors.class, Worker.class,WorkerConfig.class)

Spring 会按您说的做。你在打电话:

@ComponentScan(basePackages = "com.adobe"
, excludeFilters = 
    @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = WorkerConfig.class, WorkerExecutors.class, Worker.class))

因此 Spring 不会加载任何这些 Worker 类。这就是为什么 Spring 不会“执行”带有 @Configuration 注释的类的原因。

也就是说,您尝试做的事情对我来说没有意义。听起来你有“模块”(java类),但它们都是同一个spring上下文的一部分。如果你有一个单一的 Spring 上下文,那么你可以告诉 Spring 加载一些 @Configuration 类而不是其他一些。然后,从你的“模块”中,你可以注入你需要的任何东西。模块 1 将从模块 3 注入 Bean,但模块 2 不会。就这么简单。

如果由于某种原因您确实需要阻止模块 2 从模块 3 访问 bean,但仍然保持模块 3 从模块 1 可见,那么我会将模块 1 和模块 2 分隔在两个不同的 Spring Boot 应用程序中,而模块 3成为通用代码。但这种方法可能会破坏您当前的架构。

2019 年 3 月 29 日星期五更新

试试这个:

@SpringBootApplication
@ComponentScan(basePackages =  "com.myapp" , excludeFilters =  @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value =  MyClass2.class ) )

它对我有用。我有 MyClass 和 MyClass2,MyClass 已加载,而 MyClass2 未加载。我使用 Spring Boot 1.5.9.RELEASE 和 Spring Bom 尝试了所有依赖项。

【讨论】:

Spring 正在加载 Worker 类,这就是问题所在。我希望它不加载它们,但当前代码不起作用。另外,认为我的问题没有详细说明。模块 1 和模块 2 是独立的 Spring boot 应用程序,模块 3 是通用代码。这是我的工人班级所在的地方(包括配置)。它们希望由 Module 2 和其他模块而不是 Module 1 加载,但是 Module 1 需要 Module 3 中存在的一些其他配置类。当然,我也可以将 Module 3 分成 Module 4 以及 Module 1 从不扫描 4 但我正在寻找我提到的当前代码结构中的方法 好吧,如果模块 3 有模块 2 中需要的代码,但模块 1 中没有,那么模块 3 是真正的通用代码。我知道你知道这一点,只是指出问题所在。现在,根据我的经验,在公共代码中使用 @Configuration 并不是那么好,因为它会扫描所有子项目(或模块或任何你想调用它的东西)。对我帮助很大的是将代码放在一个共同的地方,而不是 Spring 注释,只是代码。假设您有包含一堆 Java 代码的模块 3,但没有 Spring 注释。继续阅读下一条评论-> 那么,如果模块 2 需要模块 3 中的代码,那么您需要在模块 2 中创建一个配置类,该类使用模块 3 中的类型/代码创建所有 @Beans。有意义吗?这就是要走的路。 听起来很公平。但唯一的问题是模块 3 不仅会被模块 2 调用,还会被更多模块 (4,5 ) 调用,依此类推..所以我们最终会在所有模块中复制代码..这是我想要避免的..跨度> 好吧,它实际上并没有复制代码。快速示例:我曾经在一个有 10 个 springboot 应用程序的项目中工作。它们都被配置为使用 API Key Filter bean。因此,API 密钥过滤的逻辑被放置在一个名为 APIKeyFilter 的类中,该类位于一个常见的 java 模块中。然后,每个 Spring Boot 应用都会像这样创建一个 bean:@Bean public APIKeyFilter apikeyfilter()

以上是关于从 Spring Boot 应用程序中排除 @Configuration的主要内容,如果未能解决你的问题,请参考以下文章

如何从 spring-boot-starter-parent 中排除特定依赖项

从 Spring Boot jar 中排除 data.sql

Java Spring Boot 测试:如何从测试上下文中排除 java 配置类

从 Gradle 中的 Spring Boot 中排除 Tomcat 依赖项

从 Spring Boot 单元测试中排除 Spring Cloud Config Server

Spring Boot 应用程序“bean 类的 bean 名称与现有冲突” - 如何从 3rd 方库/依赖项中排除包/类?