spring-boot-stater-mail 发送邮件耗时过长问题

文章讨论了在使用SpringBoot的JavaMailSender发送邮件时遇到的延迟问题,主要原因是获取CanonicalHostName的过程耗时。提出的解决方案包括在本地hosts文件中配置IP和域名,或者在代码中设置系统属性以避免获取CanonicalHostName。提供了相应的Java代码片段作为示例。

一、组件版本


    <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-dependencies</artifactId>
     <version>Hoxton.RELEASE</version>
 
     <!-- 邮件服务 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>

spring-boot-starter-mail 内部依赖的是 jakarta.mail 1.6.4版本。

<dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <version>2.2.1.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context-support</artifactId>
      <version>5.2.1.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>com.sun.mail</groupId>
      <artifactId>jakarta.mail</artifactId>
      <version>1.6.4</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>

 jakarta.mail 是 javax.mail 1.6版本后的重命名。

二、场景描述

        在使用 JavaMailSender.send(mimeMessage); 发送邮件时,时间太久,至少18s以上。

三、问题展现

        通过在代码中,设置mail中Session的debug日志分析,主要是两处源码耗时太久。

1. com.sun.mail.smtp.SMTPTransport 类中的726行 getLocalHost() 从而获取 CanonicalHostName

 2. org.springframework.mail.javamail.JavaMailSenderImpl 中 mimeMessage.saveChanges() 

中,内部深处也是使用了 getLocalHostName() 而获取 CanonicalHostName

三、解决方案

        解决方案有两种。

        1. 在本地的hosts文件中,配置 本地的ip与域名(或计算机名),使其可以快速获取到CanonicalHostName.

例如

                192.168.56.1 localhost1

        2.  通过在程序代码中添加系统变量以及mail的Session的变量,从而绕过,不获取CanonicalHostName。

session.getProperties().setProperty("mail.smtp.localhost", "自定义");
System.getProperties().setProperty("mail.mime.address.usecanonicalhostname", "false");

伪代码:

 @Autowired
 private JavaMailSender mailSender;

 public Boolean sendComplexEmail2(EmailBo email) throws MessagingException, IOException {

       
        // 解决本地DNS未配置 ip->域名场景下,邮件发送太慢的问题
        System.getProperties().setProperty("mail.mime.address.usecanonicalhostname", "false");
        // 获取 MimeMessage
        MimeMessage mimeMessage = mailSender.createMimeMessage();
        Session session = mimeMessage.getSession();
        // 设置 日志打印控制器
        session.setDebug(true);
		//  解决本地DNS未配置 ip->域名场景下,邮件发送太慢的问题
        session.getProperties().setProperty("mail.smtp.localhost", "myComputer");

。。。。。。		
}

 

目前只为解决问题,等有时间再深入挖掘 使用 canonicalhostname 的原因。

### Spring Boot 中 `spring-boot-data-redis` 和 `spring-boot-starter-data-redis` 的区别 #### 定义与用途 `sprng-boot-starter-data-redis` 是一个启动器(Starter),它包含了构建基于 Redis 数据存储的应用程序所需的所有依赖项。这个 Starter 自动引入了核心库,例如 `spring-data-redis` 和底层的 Redis 驱动程序(如 Jedis 或 Lettuce)。通过这种方式简化了项目的配置过程[^1]。 另一方面,`spring-boot-data-redis` 并不是一个独立的模块名称,而是通常指代由 `spring-boot-starter-data-redis` 提供的核心功能之一——即对 Redis 数据访问的支持能力。换句话说,它是 `spring-boot-starter-data-redis` 所封装的功能的一部分[^2]。 #### 主要差异总结 以下是两者的主要区别: 1. **命名含义** - `spring-boot-starter-data-redis`: 这是一个完整的 Starter 模块,用于快速集成 Redis 功能到 Spring Boot 应用中。 - `spring-boot-data-redis`: 更像是描述性的术语,表示 Spring Boot 对数据层 Redis 支持的整体概念,而不是具体的 Maven/Gradle 依赖项[^3]。 2. **依赖关系** - 当你在项目中添加 `spring-boot-starter-data-redis` 时,会自动拉取多个必要的子依赖项,其中包括但不限于: - `spring-data-redis`: 实现 Redis 数据操作的核心抽象接口。 - `lettuce-core` 或 `jedis`: Redis Java 客户端驱动程序的选择,默认情况下可能会优先选用其中之一作为默认实现。 3. **自动化配置** - 使用 `spring-boot-starter-data-redis` 后,Spring Boot 将提供一系列开箱即用的自动化配置选项来管理 Redis 连接池以及序列化策略等高级特性。这些都无需开发者额外编写繁琐的手动代码即可完成初始化工作[^2]。 4. **实际应用中的体现** 下面展示了一个简单的测试案例片段,其中展示了如何利用 `RedisTemplate` 来保存键值对并设置过期时间: ```java @SpringBootTest class CodeApplicationTests { @Autowired private RedisTemplate<String, Object> redisTemplate; @Test public void testRedisOperations(){ // 设置 key-value 到缓存里,并指定存活时间为60秒 redisTemplate.opsForValue().set("testKey","value"); redisTemplate.expire("testKey",60L, TimeUnit.SECONDS); String result = (String) redisTemplate.opsForValue().get("testKey"); Assertions.assertEquals(result,"value"); } } ``` 此代码段表明,在成功注入 `RedisTemplate` 后可以非常方便地执行各种针对 Redis 缓存的操作命令[^3]。 #### 结论 综上所述,“`spring-boot-data-redis`”更多是指向于一种逻辑上的表述形式,而 “`spring-boot-starter-data-redis`”才是具体可被加入工程文件里的组件包名。如果希望在自己的应用程序里面轻松接入 Redis,则应该直接引用后者。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值