带有 Spring AutoConfiguration 的库: spring.factories 还有什么?

der*_*erM 4 java spring spring-boot

我们打算开发一个带有 Spring 组件的库,我们所有的 Spring 应用程序都应该具有这些组件,例如连接到我们的监控、管理和管理服务的 Bean。

这个想法是利用 Springs 的“自动配置”机制。

对于初学者,我编写了一个类com.mycorp.project.basic.startup-notification.StartupNotificationPublisher.class,当“ApplicationStartedEvent”发生时,它通过我们最喜欢的消息代理(例如,它是一个日志文件)发送一条消息,向世界问好。

应通过配置类创建此类的实例com.mycorp.project.basic.startup-notification.autoconfiguration.StartupNotificationAutoConfiguration.class

package com.mycorp.project.basic.startup-notification
// ... Imports
@RequiredArgsConstructor
public class StartupNotificationPublisher {
    private final String topic;

    private final Logger messagePublisher = LoggerFactory.getLogger(StartupNotificationPublisher.class);

    @EventListener
    public void onApplicationStartedEvent(ApplicationStartedEvent event) {
        messagePublisher.info("{}: Hello, Attention, I am here!", topic);
    }
}

package com.mycorp.project.basic.startup-notification.autoconfiguration
// ... Imports
@Configuration
public class StartupNotificationAutoConfiguration {

    @ConditionalOnMissingBean
    @Bean
    StartupNotificationPublisher startupNotificationPublisher()
    {
        return new StartupNotificationPublisher("helloTopic");
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,为了使自动配置工作,我spring.factoriesMETA-INFjar 的 -Folder 中放置了一个文件(是的,它就在那里!),其中包含:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.mycorp.project.basic.startup-notification.autoconfiguration.StartupNotificationAutoConfiguration
Run Code Online (Sandbox Code Playgroud)

我想,这将使 spring 发挥其魔力,在添加依赖项时找到该文件,运行配置并创建该 bean 来发布消息。

然而,事实并非如此。只有当我将包添加到我的扫描路径时@SpringBootApplication,我才会收到消息。

我错过了什么?是否有更具体的要求,例如特殊的项目结构?我需要有一个名为 spring-boot-starter 的库或类似的库吗?

项目结构:

rootDirectory
|-src
|  |-main
|    |-java
|    | |-com/mycorp/project/basic/startup-notification
|    |                            |-autoconfiguration
|    |                            | |-StartupNotificationAutoConfiguration.java
|    |                            |-StartupNotificationPublisher.java
|    |-resources
|      |-META-INF
|        |-spring.factories
|-build.gradle
|-...etc...
Run Code Online (Sandbox Code Playgroud)

生成的罐子结构:

.jar
|-META-INF
| |-spring.factories
|-com
  |-mycorp
    |-project
      |-basic
        |-startup-notification
          |-autoconfiguration
          | |-StartupNotificationAutoConfiguration.class
          |-StartupNotificationPublisher.class
Run Code Online (Sandbox Code Playgroud)

Dav*_*vid 17

我在类似的问题上花了几天时间,这对我有用。如果你使用 Spring boot 3+,他们改变了这一切!您可以在此处找到 2.7 发行说明中记录的更改:2.7 发行说明#auto-configuration。在 2.7 版本中,他们支持新旧方式向后兼容,并将 spring.factories 标记为已弃用(弃用通知)。他们在 3.0 中完全取消了支持!您可以在此处的 2.7 -> 3.0 迁移指南中找到删除信息:spring boot 2.7 -> 3.0 迁移指南#自动配置文件。本质上,您现在需要使用注释您的顶级自动配置类,并将@AutoConfiguration完全限定名称添加到此位置的文件中;META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports; 是的,这是文件的名称。不同的自动配置类将用换行符分隔,而不是像 中那样用逗号分隔的字符串spring.factories

我希望这有帮助。

  • 我今天遇到了这个问题,在 spring boot 3.0.6 上 spring.factories 不再工作。在我将自动配置移动到新位置之前,我无法启动它。他们的文档仍然显示了旧的做法:( (2认同)

Mar*_*nik 5

Spring Factory 如果配置正确,则与组件扫描无关。

我可以确认您所做的一切都是正确的,相同的配置多次适用于我的项目。因此要跟踪发生的情况:

  1. 确保给定模块“abc”,将文件放置spring.factories在:

abc/src/main/resources/META-INF/spring.factories

  1. 确保库 jar 确实包含此文件并且它确实驻留在工件(您的 Spring Boot 应用程序)中。为此,使用 WinRar(或类似工具)打开应用程序并导航BOOT-INF/lib- jar 应该在那里 - 打开 jar 并检查该META-INF/spring.factories文件夹是否在那里。如果这里有问题,请检查pom.xml自动配置模块中的依赖项是否应定义为 Spring Boot 应用程序的依赖项。

  2. 确保配置确实加载(这意味着自动配置模块被识别):

按以下方式重写配置:

@Configuration
public class StartupNotificationAutoConfiguration {

    public StartupNotificationAutoConfiguration() {
          System.out.println("Loading the configuration StartupNotificationAutoConfiguration"); // or use logging framework
    }

   @ConditionalOnMissingBean
   @Bean
   StartupNotificationPublisher startupNotificationPublisher()
   {
    return new StartupNotificationPublisher("helloTopic");
   }
}
Run Code Online (Sandbox Code Playgroud)

如果您看到此消息,则说明自动配置模块已存在并由 spring 加载。

  1. 尝试删除@ConditionalOnMissingBean注释。如果该 bean 是在您的应用程序中定义的,那么它将优先于自动配置模块中定义的 bean。它也可能是您问题的根源。