<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Java學習

    java,spring,structs,hibernate,jsf,ireport,jfreechart,jasperreport,tomcat,jboss -----本博客已經搬家了,新的地址是 http://www.javaly.cn 如果有對文章有任何疑問或者有任何不懂的地方,歡迎到www.javaly.cn (Java樂園)指出,我會盡力幫助解決。一起進步

     

    java郵件:在簡單和復雜之間的方案

    /**
    *作者:張榮華(ahuaxuan)
    *2007-07-11
    *轉載請注明出處及作者
    */

    Javamail,論壇上由已經有很多的討論,但是俺覺得還是不夠完整,不完整不是說講的不細致,而是指不全面,而是缺少high level的全面論述,所以俺來補充一下。

    這篇文章的名字起得很古怪(估計還有人暗地里說文章名字取得如何如何,文章實質卻是水貨等等了,先不忙下結論,各位看官接著往下看便知),叫簡單和復雜之 間,為什么要取這么個奇怪的名字,搞得人一頭霧水,其實我想要表達的意思是這樣的,之前壇子上有很多人討論過如何使用javamail(包括spring 對其的封裝),也有人討論過如何通過jms發送emal,一個是簡單的api介紹,一個是比較復雜的異步方案,但是試問除了簡單使用其api難道就只能使 用jms來進行異步發送了嗎,我們可以再找到一種介于這兩者之間的方案,就是concurrent(我的建議是在普通的web應用中郵件發送不需要用 jms,但是最好也不要使用同步發送,所以普通的web應該使用concurrent來進行異步郵件發送應該是比較好的選擇)。

    在普通的web應用中,發送郵件應該只能算小任務,而使用jms來發送郵件有點殺雞用牛刀的味道,那么如果能建立一個線程池來管理這些小線程并重復使用他 們,應該來說是一個簡單有效的方案,我們可以使用concurrent包中的Executors來建立線程池,Executors是一個工廠,也是一個工 具類,我把它的api的介紹簡單的翻譯了一下(如果翻譯有誤請大家不要吝嗇手中的磚頭)

    方  法 說  明
    newCachedThreadPool() 創建一個包含新線程的線程池,池中線程的數量需要預先指定,該線程池會復用之前創建的線程(前提是該線程還是有效線程)。如果你的要執行的任務是短生命周期的任務的話,使用這種池提高性能是很具代表性的。這個方法有一個重載
    newFixedThreadPool() 創建一個線程池以復用指定數量的線程,如果當所有線程都是活動狀態時(指這些線程都在運行),那么新的任務將會等待,知道有空余的線程。如果有任何一個線 程因為在運行中發生錯誤而終結(非正常shutdown),那么如果有新的任務要并發處理,concurrent就會創建一個新的線程放入池中。
    newSingleThreadExecutor() 創建一個使用單工作線程的executor,
    newScheduledThreadPool() 可調度的線程池,池中的線程可以在某一時間延遲之后執行,也可以周期性執行
    newSingleThreadScheduledExecutor() 單一可調度的線程


    上面我重點解釋了newFixedThreadPool(),因為我們將使用newFixedThreadPool方法來創建一個線程池,這個線程池中存放的線程就是我們用來發送郵件的。代碼如下:
    Java代碼 復制代碼
    1. /** 
    2.  * 由spring管理的線程池類,返回的ExecutorService就是給我們來執行線程的 
    3. *如果不交給spring管理也是可以的,可以使用單例模式來實現同樣功能,但是poolSize   *要hardcode了 
    4.  * @author 張榮華(ahuaxuan) 
    5. * @version $Id$ 
    6.  */  
    7. public class EasyMailExecutorPool implements InitializingBean {  
    8.   
    9.     //線程池大小,spring配置文件中配置  
    10.     private int poolSize;  
    11.     private ExecutorService service;  
    12.   
    13.     public ExecutorService getService() {  
    14.         return service;  
    15.     }  
    16.   
    17.     public int getPoolSize() {  
    18.         return poolSize;  
    19.     }  
    20.   
    21.     public void setPoolSize(int poolSize) {  
    22.         this.poolSize = poolSize;  
    23.     }  
    24.   
    25.     /** 
    26.      * 在 bean 被初始化成功之后初始化線程池大小 
    27.      */  
    28.     public void afterPropertiesSet() throws Exception {  
    29.         service = Executors.newFixedThreadPool(poolSize);  
    30.     }  
    31. }  



    這樣我們就初始化了線程池的大小,接下來就是如何使用這個線程池中的線程了,我們看看MailService是如何來使用線程池中的線程的,這個類中的代碼我已經作了詳細的解釋
    Java代碼 復制代碼
    1. /** 
    2.  * 用來發送 mail 的 service, 其中有一個內部類專門用來供線程使用 
    3.  * @author 張榮華(ahuaxuan) 
    4.  * @since 2007-7-11 
    5.  * @version $Id$ 
    6.  */  
    7. public class EasyMailServieImpl implements EasyMailService{  
    8.     private static transient Log logger = LogFactory.getLog(EasyMailServieImpl.class);   
    9.       
    10.     //注入MailSender  
    11.     private JavaMailSender javaMailSender;  
    12.       
    13.     //注入線程池  
    14.     private EasyMailExecutorPool easyMailExecutorPool;  
    15.       
    16.     //設置發件人  
    17.     private String from;  
    18.       
    19.     public void setEasyMailExecutorPool(EasyMailExecutorPool easyMailExecutorPool) {  
    20.         this.easyMailExecutorPool = easyMailExecutorPool;  
    21.     }  
    22.   
    23.     public void setJavaMailSender(JavaMailSender javaMailSender) {  
    24.         this.javaMailSender = javaMailSender;  
    25.     }  
    26.       
    27.     public void setFrom(String from) {  
    28.         this.from = from;  
    29.     }  
    30.   
    31.     /** 
    32.      * 簡單的郵件發送接口,感興趣的同學可以在這個基礎上繼續添加 
    33.      * @param to 
    34.      * @param subject 
    35.      * @param text 
    36.      */  
    37.     public void sendMessage(EmailEntity email){  
    38.         if (null == email) {  
    39.             if (logger.isDebugEnabled()) {  
    40.                 logger.debug("something you need to tell here");  
    41.             }  
    42.             return;  
    43.         }  
    44.         SimpleMailMessage simpleMailMessage = new SimpleMailMessage();  
    45.           
    46.         simpleMailMessage.setTo(email.getTo());  
    47.         simpleMailMessage.setSubject(email.getSubject());  
    48.         simpleMailMessage.setText(email.getText());  
    49.         simpleMailMessage.setFrom(from);  
    50.           
    51.         easyMailExecutorPool.getService().execute(new MailRunner(simpleMailMessage));  
    52.     }  
    53.       
    54.     /** 
    55.      * 發送復雜格式郵件的接口,可以添加附件,圖片,等等,但是需要修改這個方法, 
    56.      * 如何做到添加附件和圖片論壇上有例子了,需要的同學搜一下, 
    57.      * 事實上這里的text參數最好是來自于模板,用模板生成html頁面,然后交給javamail去發送, 
    58.      * 如何使用模板來生成html見 {@link http://www.javaeye.com/topic/71430 } 
    59.      *  
    60.      * @param to 
    61.      * @param subject 
    62.      * @param text 
    63.      * @throws MessagingException 
    64.      */  
    65.     public void sendMimeMessage(EmailEntity email) throws MessagingException {  
    66.         if (null == email) {  
    67.             if (logger.isDebugEnabled()) {  
    68.                 logger.debug("something you need to tell here");  
    69.             }  
    70.             return;  
    71.         }  
    72.         MimeMessage message = javaMailSender.createMimeMessage();  
    73.         MimeMessageHelper helper = new MimeMessageHelper(message);  
    74.           
    75.         helper.setTo(email.getTo());  
    76.         helper.setFrom(from);  
    77.         helper.setSubject(email.getSubject());  
    78.           
    79.         this.addAttachmentOrImg(helper, email.getAttachment(), true);  
    80.         this.addAttachmentOrImg(helper, email.getImg(), false);  
    81.           
    82.         //這里的text是html格式的, 可以使用模板引擎來生成html模板, velocity或者freemarker都可以做到  
    83.         helper.setText(email.getText(),true);  
    84.           
    85.         easyMailExecutorPool.getService().execute(new MailRunner(message));  
    86.     }  
    87.       
    88.     /** 
    89.      * 添加附件或者是圖片 
    90.      * @param helper 
    91.      * @param map 
    92.      * @param isAttachment 
    93.      * @throws MessagingException 
    94.      */  
    95.     private void addAttachmentOrImg(MimeMessageHelper helper, Map map, boolean isAttachment) throws MessagingException {  
    96.         for (Iterator it = map.entrySet().iterator(); it.hasNext();) {  
    97.             Map.Entry entry = (Map.Entry) it.next();  
    98.             String key = (String) entry.getKey();  
    99.             String value = (String) entry.getValue();  
    100.             if (StringUtils.isNotBlank(key) && StringUtils.isNotBlank(value)) {  
    101.                 FileSystemResource file = new FileSystemResource(new File(value));  
    102.                 if (!file.exists()) continue;  
    103.                 if (isAttachment) {  
    104.                     helper.addAttachment(key, file);  
    105.                 } else {  
    106.                     helper.addInline(key, file);  
    107.                 }  
    108.             }  
    109.         }  
    110.     }  
    111.       
    112.     /** 
    113.      * 用來發送郵件的 Runnable, 該類是一個內部類,之所以使用內部類,而沒有使用嵌套類(靜態內部類), 
    114.      * 是因為內部類可以之間得到 service 的 javaMailSender 
    115.      * 每次發送郵件都會從線程池中取一個線程, 然后進行發郵件操作 
    116.      * @author ahuaxuan 
    117.      */  
    118.     private class MailRunner implements Runnable {  
    119.         SimpleMailMessage simpleMailMessage;  
    120.         MimeMessage mimeMessage;   
    121.           
    122.         /** 
    123.          * 構造簡單文本郵件 
    124.          * @param simpleMailMessage 
    125.          */  
    126.         public MailRunner(SimpleMailMessage simpleMailMessage) {  
    127.             if (mimeMessage == null) {  
    128.                 this.simpleMailMessage = simpleMailMessage;  
    129.             }  
    130.         }  
    131.           
    132.         /** 
    133.          * 構造復雜郵件,可以添加附近,圖片,等等 
    134.          * @param mimeMessage 
    135.          */  
    136.         public MailRunner(MimeMessage mimeMessage) {  
    137.             if (simpleMailMessage == null) {  
    138.                 this.mimeMessage = mimeMessage;  
    139.             }  
    140.         }  
    141.           
    142.         /** 
    143.          * 該方法將在線程池中的線程中執行 
    144.          */  
    145.         public void run() {  
    146.             try {  
    147.                 if (simpleMailMessage != null) {  
    148.                     javaMailSender.send(this.simpleMailMessage);  
    149.                 } else if (mimeMessage != null) {  
    150.                     javaMailSender.send(this.mimeMessage);  
    151.                 }  
    152.                   
    153.             } catch (Exception e) {  
    154.                 if (logger.isDebugEnabled()) {  
    155.                     logger.debug("logger something here", e);  
    156.                 }  
    157.             }       
    158.         }  
    159.     }  
    160. }  


    MailService中的EmailEntity是對郵件的抽象(我只使用了失血模型,事實上我們也可以讓這個EmailEntity來實現 Runnable接口,這樣Service中的內部類就可以去掉了,同時service中的大部分代碼就要搬到EmailEntity及其父類里了,大家 更傾向于怎么做呢?),代碼如下:
    Java代碼 復制代碼
    1. /** 
    2.  * 該類是對郵件的抽象,郵件有哪些屬性,這個類就有哪些屬性 顯然這個只是一個例子, 
    3.  * 這個例子中附帶mimemessage發送所需的附件或者圖片(如果有的話) 
    4.  * 需要使用的同學自己擴展 
    5.  *  
    6.  * @author 張榮華(ahuaxuan) 
    7. * @version $Id$ 
    8.  */  
    9. public class EmailEntity {  
    10.   
    11.     String to;  
    12.   
    13.     String subject;  
    14.   
    15.     String text;  
    16.   
    17.     //郵件附件  
    18.     Map<String, String> attachment = new HashMap<String, String>();  
    19.   
    20.     //郵件圖片  
    21.     Map<String, String> img = new HashMap<String, String>();  
    22.     //這里省去大段的getter和setter方法  
    23. }  

    接下來就是在spring的配置文件中配置這些類了,我相信對熟悉spring的人來說這不是什么大問題:
    Java代碼 復制代碼
    1. <beans>  
    2.     <bean id="javaMailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl" autowire="byName">  
    3.         <property name="host" value="${mail.host}"/>  
    4.         <property name="username" value="${mail.username}"/>  
    5.         <property name="password" value="${mail.password}"/>  
    6.     </bean>  
    7.   
    8.     <bean id="easyMailExecutorPool" class="org.zhangronghua.easymail.EasyMailExecutorPool" autowire="byName">  
    9.         <property name="poolSize">  
    10.             <value>5</value>  
    11.         </property>  
    12.     </bean>  
    13.       
    14.     <bean id="easyMailService" class="org.zhangronghua.easymail.EasyMailServieImpl" autowire="byName">  
    15.         <property name="from" value="${mail.default.from}"/>  
    16.     </bean>  
    17. </beans>  


    經過這么一番折騰之后,一個郵件發送的雛形就完成了,接著需要什么樣的郵件發送功能就可以隨意往MailService里添加內容了, 而如果需要用模板來生成html格式的郵件真的需要看http://www.javaeye.com/topic/71430這個貼了,無論你是想用velocity還是想用freemarker來做模板引擎,這個貼中的例子都是可以直接拿來使用的

    總結,如果自己起線程來發送郵件是一個非常危險的事情,如果并發一高(比如超過20),服務器估計就快撐不住了,而如果使用jms來異步發送郵件,學習的 曲線高,成本也高,我不建議為了一個小小的郵件發送就在項目中導入jms(之所以這樣說是因為還有很多項目就是基于webservice的,那么使用 jms來調度webservice是一個不錯的選擇),所以使用線程池來實現這個異步的功能既安全又簡單,這個例子是開源的,大家可以在自己的項目中隨意 修改,隨意封裝。

    要注意的是,concurrent在jdk5.0以上版本中才有,如果你使用的是1.4的jdk需要單獨下載concurrent包。

    作者:張榮華,未經作者同意不得隨意轉載!

    posted on 2008-10-16 08:54 找個美女做老婆 閱讀(762) 評論(0)  編輯  收藏


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     

    導航

    統計

    公告

    本blog已經搬到新家了, 新家:www.javaly.cn
     http://www.javaly.cn

    常用鏈接

    留言簿(6)

    隨筆檔案

    文章檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 亚洲国产精品嫩草影院在线观看| 亚洲日韩国产精品乱-久| 2019中文字幕在线电影免费| 亚洲成a人片在线观看中文app| 一二三四在线播放免费观看中文版视频 | 亚洲成?v人片天堂网无码| a级毛片免费在线观看| 亚洲女人影院想要爱| 亚洲Av无码乱码在线播放| 亚洲一区二区在线免费观看| 亚洲色精品三区二区一区| 国产亚洲老熟女视频| 国产精品成人观看视频免费| 国产成人高清亚洲一区久久| 日本亚洲欧洲免费天堂午夜看片女人员 | 亚洲色一区二区三区四区| 国产性爱在线观看亚洲黄色一级片 | 精品一卡2卡三卡4卡免费视频| 亚洲一卡2卡3卡4卡国产网站| 免费人成激情视频| 久久久久av无码免费网| 免费无码午夜福利片| 亚洲电影在线播放| 亚洲情a成黄在线观看| 免费A级毛片无码免费视| 热久久这里是精品6免费观看| 亚洲熟妇AV一区二区三区宅男| 亚洲爆乳精品无码一区二区三区 | 在线免费观看伊人三级电影| 亚洲免费福利在线视频| 国产av无码专区亚洲av桃花庵| 国产男女性潮高清免费网站| 日本免费网站视频www区| 久久高潮一级毛片免费| 亚洲s码欧洲m码吹潮| 亚洲午夜电影在线观看高清| 亚洲大尺度无码专区尤物| 亚洲一区日韩高清中文字幕亚洲| 操美女视频免费网站| 青娱乐免费在线视频| 在线免费观看亚洲|