在web项目中使用线程池发送邮件实例

使用线程池优化邮件发送效率:易用邮件服务实践
本文介绍了如何利用线程池技术优化邮件发送过程,通过创建一个易于管理的邮件服务类,实现了邮件发送的高效执行。通过Spring管理的线程池配置,简化了邮件发送逻辑,支持简单文本邮件和复杂格式邮件发送,并提供了附件和图片的添加功能。此实践不仅提高了邮件发送的性能,还降低了资源消耗。

在普通的web应用中,发送邮件应该只能算小任务,而使用jms来发送邮件有点杀鸡用牛刀的味道,那么如果能建立一个线程池来管理这些小线程并重复使用他们,应该来说是一个简单有效的方案,我们可以使用concurrent包中的Executors来建立线程池,Executors是一个工厂,也是一个工具类,我把它的api的介绍简单的翻译了一下(如果翻译有误请大家不要吝啬手中的砖头)
/** 
 * 由spring管理的线程池类,返回的ExecutorService就是给我们来执行线程的 
*如果不交给spring管理也是可以的,可以使用单例模式来实现同样功能,但是poolSize   *要hardcode了 
 * @author 张荣华(ahuaxuan) 
* @version $Id$ 
 */  
public class EasyMailExecutorPool implements InitializingBean {  
  
  //线程池大小,spring配置文件中配置  
  private int poolSize;  
  private ExecutorService service;  
  
  public ExecutorService getService() {  
    return service;  
  }  
  
  public int getPoolSize() {  
    return poolSize;  
  }  
  
  public void setPoolSize(int poolSize) {  
    this.poolSize = poolSize;  
  }  
  
  /** 
   * 在 bean 被初始化成功之后初始化线程池大小 
   */  
  public void afterPropertiesSet() throws Exception {  
    service = Executors.newFixedThreadPool(poolSize);  
  }  
}  



这样我们就初始化了线程池的大小,接下来就是如何使用这个线程池中的线程了,我们看看MailService是如何来使用线程池中的线程的,这个类中的代码我已经作了详细的解释 
代码
/** 
 * 用来发送 mail 的 service, 其中有一个内部类专门用来供线程使用 
 * @author 张荣华(ahuaxuan) 
 * @since 2007-7-11 
 * @version $Id$ 
 */  
public class EasyMailServieImpl implements EasyMailService{  
  private static transient Log logger = LogFactory.getLog(EasyMailServieImpl.class);   
    
  //注入MailSender  
  private JavaMailSender javaMailSender;  
    
  //注入线程池  
  private EasyMailExecutorPool easyMailExecutorPool;  
    
  //设置发件人  
  private String from;  
    
  public void setEasyMailExecutorPool(EasyMailExecutorPool easyMailExecutorPool) {  
    this.easyMailExecutorPool = easyMailExecutorPool;  
  }  
  
  public void setJavaMailSender(JavaMailSender javaMailSender) {  
    this.javaMailSender = javaMailSender;  
  }  
    
  public void setFrom(String from) {  
    this.from = from;  
  }  
  
  /** 
   * 简单的邮件发送接口,感兴趣的同学可以在这个基础上继续添加 
   * @param to 
   * @param subject 
   * @param text 
   */  
  public void sendMessage(EmailEntity email){  
    if (null == email) {  
      if (logger.isDebugEnabled()) {  
        logger.debug("something you need to tell here");  
      }  
      return;  
    }  
    SimpleMailMessage simpleMailMessage = new SimpleMailMessage();  
      
    simpleMailMessage.setTo(email.getTo());  
    simpleMailMessage.setSubject(email.getSubject());  
    simpleMailMessage.setText(email.getText());  
    simpleMailMessage.setFrom(from);  
      
    easyMailExecutorPool.getService().execute(new MailRunner(simpleMailMessage));  
  }  
    
  /** 
   * 发送复杂格式邮件的接口,可以添加附件,图片,等等,但是需要修改这个方法, 
   * 如何做到添加附件和图片论坛上有例子了,需要的同学搜一下, 
   * 事实上这里的text参数最好是来自于模板,用模板生成html页面,然后交给javamail去发送, 
   * 如何使用模板来生成html见 {@link http://www.iteye.com/topic/71430 } 
   *  
   * @param to 
   * @param subject 
   * @param text 
   * @throws MessagingException 
   */  
  public void sendMimeMessage(EmailEntity email) throws MessagingException {  
    if (null == email) {  
      if (logger.isDebugEnabled()) {  
        logger.debug("something you need to tell here");  
      }  
      return;  
    }  
    MimeMessage message = javaMailSender.createMimeMessage();  
    MimeMessageHelper helper = new MimeMessageHelper(message);  
      
    helper.setTo(email.getTo());  
    helper.setFrom(from);  
    helper.setSubject(email.getSubject());  
      
    this.addAttachmentOrImg(helper, email.getAttachment(), true);  
    this.addAttachmentOrImg(helper, email.getImg(), false);  
      
    //这里的text是html格式的, 可以使用模板引擎来生成html模板, velocity或者freemarker都可以做到  
    helper.setText(email.getText(),true);  
      
    easyMailExecutorPool.getService().execute(new MailRunner(message));  
  }  
    
  /** 
   * 添加附件或者是图片 
   * @param helper 
   * @param map 
   * @param isAttachment 
   * @throws MessagingException 
   */  
  private void addAttachmentOrImg(MimeMessageHelper helper, Map map, boolean isAttachment) throws MessagingException {  
    for (Iterator it = map.entrySet().iterator(); it.hasNext();) {  
      Map.Entry entry = (Map.Entry) it.next();  
      String key = (String) entry.getKey();  
      String value = (String) entry.getValue();  
      if (StringUtils.isNotBlank(key) && StringUtils.isNotBlank(value)) {  
        FileSystemResource file = new FileSystemResource(new File(value));  
        if (!file.exists()) continue;  
        if (isAttachment) {  
          helper.addAttachment(key, file);  
        } else {  
          helper.addInline(key, file);  
        }  
      }  
    }  
  }  
    
  /** 
   * 用来发送邮件的 Runnable, 该类是一个内部类,之所以使用内部类,而没有使用嵌套类(静态内部类), 
   * 是因为内部类可以之间得到 service 的 javaMailSender 
   * 每次发送邮件都会从线程池中取一个线程, 然后进行发邮件操作 
   * @author ahuaxuan 
   */  
  private class MailRunner implements Runnable {  
    SimpleMailMessage simpleMailMessage;  
    MimeMessage mimeMessage;   
      
    /** 
     * 构造简单文本邮件 
     * @param simpleMailMessage 
     */  
    public MailRunner(SimpleMailMessage simpleMailMessage) {  
      if (mimeMessage == null) {  
        this.simpleMailMessage = simpleMailMessage;  
      }  
    }  
      
    /** 
     * 构造复杂邮件,可以添加附近,图片,等等 
     * @param mimeMessage 
     */  
    public MailRunner(MimeMessage mimeMessage) {  
      if (simpleMailMessage == null) {  
        this.mimeMessage = mimeMessage;  
      }  
    }  
      
    /** 
     * 该方法将在线程池中的线程中执行 
     */  
    public void run() {  
      try {  
        if (simpleMailMessage != null) {  
          javaMailSender.send(this.simpleMailMessage);  
        } else if (mimeMessage != null) {  
          javaMailSender.send(this.mimeMessage);  
        }  
                
            } catch (Exception e) {  
              if (logger.isDebugEnabled()) {  
                logger.debug("logger something here", e);  
              }  
            }       
    }  
  }  
}  



MailService中的EmailEntity是对邮件的抽象(我只使用了失血模型,事实上我们也可以让这个EmailEntity来实现Runnable接口,这样Service中的内部类就可以去掉了,同时service中的大部分代码就要搬到EmailEntity及其父类里了,大家更倾向于怎么做呢?),代码如下: 
代码
/** 
 * 该类是对邮件的抽象,邮件有哪些属性,这个类就有哪些属性 显然这个只是一个例子, 
 * 这个例子中附带mimemessage发送所需的附件或者图片(如果有的话) 
 * 需要使用的同学自己扩展 
 *  
 * 
@author 张荣华(ahuaxuan) 
@version $Id$ 
 
*/  
public class EmailEntity {  
  
  String to;  
  
  String subject;  
  
  String text;  
  
  
//邮件附件  
  Map  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值