We intend to develop a library with Spring Components that all of our Spring Applications should have, like Beans that connect to our monitoring, administration and ochestration services.
The idea was, to make use of Springs’ “AutoConfiguration”-mechanism.
For a Starter I wrote a class com.mycorp.project.basic.startup-notification.StartupNotificationPublisher.class
which, uppon “ApplicationStartedEvent” sends a Message via our favorite message broker (which for the exmample shall be a log file), saying hello to the world.
An instance of this class shall be created through the configuration class 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"); } }
Finally, to make the autoconfiguration work, I placed a File spring.factories
in the META-INF
-Folder of the jar (yes, it is there!), containing:
org.springframework.boot.autoconfigure.EnableAutoConfiguration= com.mycorp.project.basic.startup-notification.autoconfiguration.StartupNotificationAutoConfiguration
I assumed, this will make spring do its magic, find that file when I add the dependency, run the configuration and create that bean to publish the message.
This however is not what happens. Only when I add the package to the scan path of my @SpringBootApplication
, I will get my message.
What did I miss? Are there more specific requirements like special project structures? Do I need to have a library called spring-boot-starter or anything like that?
- Not a Duplicate of this Question: That one is about Spring Cloud Config which we don’t use
- Not a Duplicate of any of the Questions where spring.factories does not end up in META-INF in the .jar, because in my case it is there.
ProjectStructure:
rootDirectory |-src | |-main | |-java | | |-com/mycorp/project/basic/startup-notification | | |-autoconfiguration | | | |-StartupNotificationAutoConfiguration.java | | |-StartupNotificationPublisher.java | |-resources | |-META-INF | |-spring.factories |-build.gradle |-...etc...
Resulting Jar Structure:
.jar |-META-INF | |-spring.factories |-com |-mycorp |-project |-basic |-startup-notification |-autoconfiguration | |-StartupNotificationAutoConfiguration.class |-StartupNotificationPublisher.class
Advertisement
Answer
Spring Factories, if configured correctly, have nothing to do with component scanning.
I can confirm that you did everything right, the same configuration worked for my projects many times. So to track what happens:
- Make sure that given the module “abc”, you place the
spring.factories
file in:
abc/src/main/resources/META-INF/spring.factories
Make sure that the library jar indeed contains this file and it indeed resides in the artifact (your spring boot application). For that open the application with WinRar (or similar tool) and nagivate to
BOOT-INF/lib
– the jar should be there – open the jar and check thatMETA-INF/spring.factories
folder is there. If something is wrong here, check the dependencies inpom.xml
the autoconfiguration module should be defined as a dependency of your spring boot application.Make sure that the configuration indeed loads (which means in turn the autoconfig module is recognized):
Rewrite the configuration in the following way:
@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"); } }
If you see this message, then auto-configuration module is there and gets loaded by spring.
- Try to Remove
@ConditionalOnMissingBean
annotation. If the bean is defined in your application it will take precendence over beans defined in auto-configuration modules anyway. It can be a source of your issue as well.