命名规则
官方的 starter 的命名格式为 spring-boot-starter-{xxxx};第三方我们自己的命名格式为 {xxxx}-spring-boot-starter。
自定义一个Starter
在这里以实现一个自定义的发邮件的starter为例,命名为mail-spring-boot-starter。
pom
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.yu</groupId>
<artifactId>mail-spring-boot-starter</artifactId>
<version>0.0.1</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
<jar.javax.mail.version>1.6.1</jar.javax.mail.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>${jar.javax.mail.version}</version>
</dependency>
</dependencies>
</project>
配置文件
发邮件时需要我们配置邮件的信息,所以我们需要定义一个
MailProperties来自动装配这些信息。
package com.yu.mail.starter.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* 邮件属性
* @author yuhh
* @date 2021/5/24 17:17
*/
@ConfigurationProperties(prefix = "mail.service")
public class MailProperties {
/** 邮件主机 */
private String mailHost;
/** 邮件主机端口 */
private Integer mailPort;
/** 邮件主机用户名 */
private String mailUserName;
/** 邮件主机授权码 */
private String mailPassword;
/** 发件方邮箱 */
private String mailEmailFrom;
/** 邮件发送超时时间 */
private String mailTimeout;
/** 邮件发送方昵称 */
private String mailPersonal;
/** 是否发送 */
private Boolean isSend;
/** 收件人 */
private String sendEmail;
public String getMailHost() {
return mailHost;
}
public void setMailHost(String mailHost) {
this.mailHost = mailHost;
}
public Integer getMailPort() {
return mailPort;
}
public void setMailPort(Integer mailPort) {
this.mailPort = mailPort;
}
public String getMailUserName() {
return mailUserName;
}
public void setMailUserName(String mailUserName) {
this.mailUserName = mailUserName;
}
public String getMailPassword() {
return mailPassword;
}
public void setMailPassword(String mailPassword) {
this.mailPassword = mailPassword;
}
public String getMailEmailFrom() {
return mailEmailFrom;
}
public void setMailEmailFrom(String mailEmailFrom) {
this.mailEmailFrom = mailEmailFrom;
}
public String getMailTimeout() {
return mailTimeout;
}
public void setMailTimeout(String mailTimeout) {
this.mailTimeout = mailTimeout;
}
public String getMailPersonal() {
return mailPersonal;
}
public void setMailPersonal(String mailPersonal) {
this.mailPersonal = mailPersonal;
}
public Boolean getSend() {
return isSend;
}
public void setSend(Boolean send) {
isSend = send;
}
public String getSendEmail() {
return sendEmail;
}
public void setSendEmail(String sendEmail) {
this.sendEmail = sendEmail;
}
}
使用ConfigurationProperties注解获取配置文件信息,prefix属性表示需要获取的配置信息的前缀。
邮件服务类
package com.yu.mail.starter.service;
import com.yu.mail.starter.configs.MailSender;
import com.yu.mail.starter.exceptions.MailException;
import com.yu.mail.starter.properties.MailProperties;
import com.yu.mail.starter.utils.ThreadUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.InputStreamSource;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.util.StringUtils;
import javax.mail.internet.MimeMessage;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 邮件服务类
* @author yuhh
* @date 2021-05-24 17:24
**/
public class MailService {
/** logger */
private static final Logger logger = LoggerFactory.getLogger(MailService.class);
/** 邮件线程名 */
private static final String MAIL_THREAD_NAME = "mailThread";
/** 邮件线程池 */
private static final ThreadPoolExecutor SEND_MAIL_EXECUTOR = ThreadUtil.buildThreadPool(MAIL_THREAD_NAME);
private MailProperties mailProperties;
private JavaMailSenderImpl mailSender;
/**
* 发送邮件--以html格式
* @param to 接受人,多个以","分割
* @param subject 主题
* @param html 发送内容(html代码)
* @author yuhh
* @date 2019/11/27 16:37
*/
public void sendMailForHtml(String to, String subject, String html) {
sendMailForHtmlHaveAttachment(to, subject, html, null, null);
}
/**
* 发送邮件--以html格式
* @param subject 主题
* @param html 发送内容(html代码)
* @author yuhh
* @date 2019/11/27 16:37
*/
public void sendMailForHtml(String subject, String html) {
sendMailForHtmlHaveAttachment(mailProperties.getSendEmail(), subject, html, null, null);
}
/**
* 发送邮件--普通文本
* @param to 接受人,多个以","分割
* @param subject 主题
* @param text 发送内容
* @author yuhh
* @date 2019/11/27 16:37
*/
public void sendMailBasic(String to, String subject, String text) {
sendMail(to, subject, text, false, null, null);
}
/**
* 发送邮件--普通文本
* @param subject 主题
* @param text 发送内容
* @author yuhh
* @date 2019/11/27 16:37
*/
public void sendMailBasic(String subject, String text) {
sendMail(mailProperties.getSendEmail(), subject, text, false, null, null);
}
/**
* 发送邮件--以html格式,带附件
* @param to 接受人,多个以","分割
* @param subject 主题
* @param html 发送内容(html代码)
* @param suffixName 附件后缀名
* @param inputStreamSource 文件inputStreamSource
* @author yuhh
* @date 2019/11/27 16:37
*/
public void sendMailForHtmlHaveAttachment(String to, String subject, String html, String suffixName, InputStreamSource inputStreamSource) {
sendMail(to, subject, html, true, suffixName, inputStreamSource);
}
/**
* 发送邮件--以html格式,带附件
* @param subject 主题
* @param html 发送内容(html代码)
* @param suffixName 附件后缀名
* @param inputStreamSource 文件inputStreamSource
* @author yuhh
* @date 2019/11/27 16:37
*/
public void sendMailForHtmlHaveAttachment(String subject, String html, String suffixName, InputStreamSource inputStreamSource) {
sendMail(mailProperties.getSendEmail(), subject, html, true, suffixName, inputStreamSource);
}
/**
* 发送邮件
* @param to 接受人,多个以","分割
* @param subject 主题
* @param test 发送内容
* @param isHtml 发送内容是否是html代码
* @param suffixName 附件后缀名
* @param inputStreamSource 文件inputStreamSource
* @author yuhh
* @date 2019/11/27 16:37
*/
private void sendMail(String to, String subject, String test, boolean isHtml,
String suffixName, InputStreamSource inputStreamSource){
if (!mailProperties.getSend()){
logger.info("配置无需发送邮件");
return;
}
if (StringUtils.isEmpty(to)){
throw new MailException("收件人为空");
}
if (StringUtils.isEmpty(subject)){
throw new MailException("邮件主题为空");
}
if (StringUtils.isEmpty(test)){
throw new MailException("邮件内容为空");
}
MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper messageHelper = getMessageHelper(mimeMessage, subject, test, isHtml, suffixName, inputStreamSource);
SEND_MAIL_EXECUTOR.execute(new SendMailThread(messageHelper, mimeMessage, to));
}
/**
* 获取邮件内容
* @param mimeMessage 邮件发送器信息
* @param subject 主题
* @param test 发送内容
* @param isHtml 发送内容是否是html代码
* @param suffixName 附件后缀名
* @param inputStreamSource 文件inputStreamSource
* @return org.springframework.mail.javamail.MimeMessageHelper
* @author yuhh
* @date 2019/11/28 14:38
*/
private MimeMessageHelper getMessageHelper(MimeMessage mimeMessage, String subject, String test, boolean isHtml,
String suffixName, InputStreamSource inputStreamSource) {
try {
// 设置utf-8或GBK编码,否则邮件会有乱码
MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
messageHelper.setFrom(mailProperties.getMailEmailFrom(), mailProperties.getMailPersonal());
messageHelper.setSubject(subject);
messageHelper.setText(test, isHtml);
if (inputStreamSource != null) {
messageHelper.addAttachment(subject + suffixName, inputStreamSource);
}
return messageHelper;
} catch (Exception e) {
logger.error("构建邮件内容出现异常", e);
}
return null;
}
/**
* 发送邮件线程类
* @author yuhh
* @date 2019/11/28 15:34
*/
private class SendMailThread implements Runnable{
/** 邮件内容 */
private final MimeMessageHelper messageHelper;
/** 邮件发送器 */
private final MimeMessage mimeMessage;
/** 接受人,多个以","分割 */
private final String to;
private SendMailThread(MimeMessageHelper messageHelper, MimeMessage mimeMessage, String to){
this.messageHelper = messageHelper;
this.mimeMessage = mimeMessage;
this.to = to;
}
@Override
public void run() {
try{
messageHelper.setTo(to.split(","));
mailSender.send(mimeMessage);
} catch (Exception e) {
logger.error("发送给‘{}’的邮件异常", to, e);
}
}
}
public MailService(MailProperties mailProperties, MailSender mailSender){
this.mailProperties = mailProperties;
this.mailSender = mailSender.createMailSender();
}
public MailService(){}
}
工具类和自定义异常就不贴出来了,需要的话去下方的码云地址自取。
自动配置类
package com.yu.mail.starter.configs;
import com.yu.mail.starter.service.MailService;
import com.yu.mail.starter.properties.MailProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
/**
* 邮件自动配置类
* @author yuhh
* @date 2021-05-24 17:30
**/
@Configuration
@ConditionalOnClass(MailService.class)
@EnableConfigurationProperties(MailProperties.class)
public class MailAutoConfig {
@Resource
private MailProperties properties;
@Bean
@ConditionalOnMissingBean()
public MailSender mailSender(){
return new MailSender(properties);
}
@Bean
@ConditionalOnMissingBean()
public MailService mailService() {
return new MailService(properties, this.mailSender());
}
}
Configuration:表明这是一个配置类。
ConditionalOnClass:当前类路径下有指定的类的条件下,才会实例化一个Bean。
EnableConfigurationProperties:使使用 @ConfigurationProperties 注解的类生效。
Resource:引入一个bean。
Bean:声明这是一个bean。
ConditionalOnMissingBean:当给定的bean不存在时,则实例化当前Bean。
MailSender类也不贴出来了,如有需要请自取。
使starter生效
1:通过SpringBoot的SPI的机制来去加载我们的starter,首先需要在META-INF下新建一个spring.factories文件,内容为:key为org.springframework.boot.autoconfigure.EnableAutoConfiguration, value是我们的自动配置类的全限定名。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.yu.mail.starter.configs.MailAutoConfig
2:需要我们在Spring Boot
应用时主动声明启用该starter
才生效,通过自定义一个@Enable
注解然后在把自动配置类通过Import
注解引入进来。
import java.lang.annotation.*;
/**
* mail starter生效声明注解
* @author yuhh
* @date 2021-05-26 17:00
**/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({MailAutoConfig.class})
public @interface EnableMail {
}
然后在需要使用该starter的springboot启动类上增加@EnableMail就行了。
默认配置
mail:
service:
mailHost:
mailPort:
mailUserName:
mailPassword:
mailEmailFrom:
mailTimeout:
send: true