javaspring-bootspring-autoconfiguration

Is it possible to use an Auto-configured Bean in my custom Auto-configuration library?


I leveraged the Spring JavaMailSender and implemented a custom MailService which uses Thymeleaf and the Spring JavaMailSender to provide high-level service methods. This worked fine.

Now I needed the same functionality in another application. So I extracted that service into a library and used Auto-configuration to get it wired into my applications.

Library and application both use Spring version 3.3.2 and Java 17.

In my library-POM I have those dependencies:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

and my application depends on my library:

        <dependency>
            <groupId>com.acme.library</groupId>
            <artifactId>lib-spring-mail</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>

The @AutoConfiguration annotated class looks like:

@AutoConfiguration(after = { MailSenderAutoConfiguration.class,
                             ThymeleafAutoConfiguration.class})
@ConditionalOnClass({JavaMailSender.class, TemplateEngine.class})
public class MailAutoConfiguration {

    @Autowired
    private JavaMailSender mailSender;

    @Autowired
    private TemplateEngine templateEngine;

    @Bean
    @ConditionalOnMissingBean
    public MailService mailService() {
        return new MailService(mailSender, templatingService());
    }

    @Bean
    @ConditionalOnMissingBean
    public TemplatingService templatingService() {
        return new TemplatingService(templateEngine);
    }
}

and the org.springframework.boot.autoconfigure.AutoConfiguration.imports file looks like this:

org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration

Although that compiles without problems, when starting the application I get this error message:

Field mailSender in com.acme.library.spring.mail.MailAutoConfiguration required a bean of type 'org.springframework.mail.javamail.JavaMailSender' that could not be found.

The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)

Action:

Consider defining a bean of type 'org.springframework.mail.javamail.JavaMailSender' in your configuration.

The underlying exception is:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.mail.javamail.JavaMailSender' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1880) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1406) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1353) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:784) ~[spring-beans-6.1.11.jar:6.1.11]

Although the two starter dependencies should be found by my application as transitive dependencies of my lib's POM, I explicitely added them to the application's POM. However, this did not change the error

How can I use the JavaMailSender that is preconfigured by Spring-Boot in my library? Is this even possible?


Solution

  • You need to create org.springframework.boot.autoconfigure.AutoConfiguration.imports file in META-INF/spring folder.

    Inside you need to list your configurations FQN. One on each line.

    Make sure you have

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-autoconfigure</artifactId>
    </dependency>
    

    in dependencies. It actually contains all autoconfigurers for spring-boot,