能否在自定义自动配置库中使用Spring自动配置的JavaMailSender?
我曾基于Spring JavaMailSender实现自定义MailService,结合Thymeleaf提供高层服务方法,运行正常。为在其他应用复用该功能,将其提取为库并通过自动配置实现注入。库与应用均使用Spring 3.3.2和Java 17。
库POM依赖
<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>
应用依赖库
<dependency> <groupId>com.acme.library</groupId> <artifactId>lib-spring-mail</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency>
自动配置类
@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); } }
org.springframework.boot.autoconfigure.AutoConfiguration.imports文件内容
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration
启动报错
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.
底层异常:
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]
即使显式在应用POM中添加spring-boot-starter-mail和spring-boot-starter-thymeleaf依赖,错误依旧。
1. 修正AutoConfiguration.imports文件
该文件用于告知Spring Boot需要加载的自动配置类。当前仅添加了Spring官方的MailSenderAutoConfiguration,但未包含自定义的MailAutoConfiguration,导致自定义配置加载时机错误。将文件内容修改为自定义自动配置类的全限定名:
com.acme.library.spring.mail.MailAutoConfiguration
注:MailSenderAutoConfiguration会通过spring-boot-starter-mail的自动配置机制自动导入,无需手动添加。
2. 补充条件注解,确保依赖Bean存在
原@ConditionalOnClass仅检查类是否存在,但无法保证对应的Bean已被创建(比如Spring Mail的自动配置需要应用配置spring.mail.*属性才会生成JavaMailSender bean)。在MailAutoConfiguration上添加@ConditionalOnBean,确保只有当依赖的Bean存在时才加载自定义配置:
@AutoConfiguration(after = { MailSenderAutoConfiguration.class, ThymeleafAutoConfiguration.class}) @ConditionalOnClass({JavaMailSender.class, TemplateEngine.class}) @ConditionalOnBean({JavaMailSender.class, TemplateEngine.class}) // 新增此注解 public class MailAutoConfiguration { // ... 其余代码 }
3. 改用构造器注入替代字段注入
Spring推荐使用构造器注入,这种方式能明确依赖关系,避免字段注入的初始化时机问题。修改自动配置类的注入方式:
@AutoConfiguration(after = { MailSenderAutoConfiguration.class, ThymeleafAutoConfiguration.class}) @ConditionalOnClass({JavaMailSender.class, TemplateEngine.class}) @ConditionalOnBean({JavaMailSender.class, TemplateEngine.class}) public class MailAutoConfiguration { private final JavaMailSender mailSender; private final TemplateEngine templateEngine; // 构造器注入 public MailAutoConfiguration(JavaMailSender mailSender, TemplateEngine templateEngine) { this.mailSender = mailSender; this.templateEngine = templateEngine; } @Bean @ConditionalOnMissingBean public MailService mailService() { return new MailService(mailSender, templatingService()); } @Bean @ConditionalOnMissingBean public TemplatingService templatingService() { return new TemplatingService(templateEngine); } }
4. 确保应用配置Spring Mail必要属性
Spring Boot的MailSenderAutoConfiguration只有在配置了邮件服务器相关属性时才会创建JavaMailSender bean。在应用的application.properties或application.yaml中添加配置:
# 示例SMTP配置 spring.mail.host=smtp.example.com spring.mail.port=587 spring.mail.username=your-email@example.com spring.mail.password=your-email-password spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.starttls.enable=true
5. 验证自动配置加载情况
在应用配置中添加debug=true,启动后查看日志中AutoConfigurationReport相关内容,确认:
MailSenderAutoConfiguration已生效并创建了JavaMailSenderbeanMailAutoConfiguration在MailSenderAutoConfiguration之后加载
内容的提问来源于stack exchange,提问作者Matthias Kuespert

