日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > php >内容正文

php

php cdi_CDI和EJB:在事务成功时发送异步邮件

發布時間:2023/12/3 php 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 php cdi_CDI和EJB:在事务成功时发送异步邮件 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

php cdi

再次問好! :)

這次,我選擇了一項常見任務,我認為大多數情況下都以錯誤的方式完成:發送電子郵件。 并非所有人都不知道電子郵件API的工作方式,例如JavaMail或Apache的commons-email 。 我通??吹降囊粋€問題是,它們低估了使發送郵件例程異步的需求,并且該例程也應該僅在基礎事務成功提交(大多數情況下)時運行。

想一想用戶在線購物的常見用例。 完成后,他可能希望接收訂單確認電子郵件。 下訂單的過程有點復雜:我們通常會在許多不同的表中插入記錄,也可能會刪除記錄以從庫存中刪除物品等。 當然,所有這些都必須在單個原子事務中完成:

//A sample EJB method //(using CMT for transaction management) public void saveOrder() {//saving some productsentityManager.persist(product1);entityManager.persist(product2);//removing them from stockentityManager.remove(product1);//and at last, we have to send that emailsendOrderConfirmationMail(); //the transaction has not yet been commited by this point }

就像上面的偽代碼一樣,我們通常會努力將事務邏輯排除在代碼之外。 也就是說,我們使用CMT(容器管理的事務)來使容器為我們做所有事情,并使代碼更整潔。 我們的方法調用完成這樣的權利后 ,EJB容器提交我們的事務。 這是問題編號1:當調用sendOrderConfirmationMail()方法時,我們無法知道事務是否成功。 用戶可能會收到不存在的訂單的確認。

如果您尚未意識到這一點,則只需使用您的任何代碼進行測試。 在對我們的封閉方法調用結束之前,對EntityManager.persist()的那些調用不會觸發任何數據庫命令。 只需設置一個斷點,然后自己看看即可。 我已經多次看到這樣的困惑。

因此,在發生回滾的情況下,我們無需發送任何電子郵件。 發生問題的原因有很多:系統故障,某些業務規則可能會拒絕購買,信用卡驗證等。

因此,我們已經知道,使用CMT時,我們很難知道交易何時成功。 下一個問題是使郵件例程異步,完全獨立于我們的訂購例程。 想象一下,如果訂購過程一切正常,但是嘗試發送電子郵件時發生一些異常怎么辦? 我們是否應該僅因為無法發送確認郵件而回滾所有內容? 我們是否應該僅僅因為我們的郵件服務器表現不佳而真的阻止用戶在我們的商店購買商品?

我知道這樣的業務需求可以任意選擇,但是請記住,通常希望使發送郵件的固有延遲不干擾訂單處理。 大多數時候,處理訂單是我們的主要目標。 諸如發送電子郵件之類的低優先級任務甚至可以推遲到服務器負載較低的時候。

開始了

為了解決這個問題,我選擇了一種純Java EE方法。 無需使用第三方API。 我們的環境包括:

  • JDK 7或更高版本。
  • Java EE 7(JBoss Wildfly 8.1.0)
  • CDI 1.1
  • EJB 3.2
  • JavaMail 1.5

我已經建立了一個小型網絡項目,因此您可以看到所有工作, 如果需要 , 可以在此處下載 。

在深入研究代碼之前,請簡要觀察一下:下面顯示的解決方案主要包括CDI事件和EJB異步調用。 這是因為CDI 1.1規范不提供異步事件處理。 似乎仍在為CDI 2.0規范進行討論。 因此,純CDI方法可能會比較棘手。 我并不是說這是不可能的,我什至沒有嘗試過。

該代碼示例僅是一個“注冊客戶”用例的信條。 我們將在其中發送電子郵件以確認用戶注冊的位置。 總體架構如下所示:

該代碼示例還提供了一個“失敗測試用例”,因此您實際上可以看到,在進行回滾時沒有發送電子郵件。 我只是在這里向您展示“幸福的道路”,從托管Bean調用我們的CustomerService EJB開始。 沒什么有趣的,只是樣板:

在我們的CustomerService EJB內部,事情開始變得有趣。 通過使用CDI API,我們可以在saveSuccess()方法的末尾觸發MailEvent事件:

@Stateless public class CustomerService {@Injectprivate EntityManager em;@Injectprivate Event<MailEvent> eventProducer;public void saveSuccess() {Customer c1 = new Customer();c1.setId(1L);c1.setName("John Doe");em.persist(c1);sendEmail();}private void sendEmail() {MailEvent event = new MailEvent();event.setTo("some.email@foo.com");event.setSubject("Async email testing");event.setMessage("Testing email");eventProducer.fire(event); //firing event!} }

MailEvent類只是代表我們事件的常規POJO。 它封裝了有關電子郵件的信息:收件人,主題,文本消息等:

public class MailEvent {private String to; //recipient addressprivate String message;private String subject;//getters and setters }

如果您是CDI的新手,并且對此事件仍然有些困惑, 請閱讀docs 。 它應該給您一個想法。

接下來是時候使用事件觀察器MailService EJB了。 這是一個簡單的EJB,帶有一些JavaMail魔術和一些應注意的注釋

@Singleton public class MailService {@Injectprivate Session mailSession; //more on this later@Asynchronous@Lock(LockType.READ)public void sendMail(@Observes(during = TransactionPhase.AFTER_SUCCESS) MailEvent event) {try {MimeMessage m = new MimeMessage(mailSession);Address[] to = new InternetAddress[] {new InternetAddress(event.getTo())};m.setRecipients(Message.RecipientType.TO, to);m.setSubject(event.getSubject());m.setSentDate(new java.util.Date());m.setContent(event.getMessage(),"text/plain");Transport.send(m);} catch (MessagingException e) {throw new RuntimeException(e);}} }

就像我說的那樣,這只是一個常規的EJB。 使此類成為事件觀察者,更確切地說是sendMail()方法的原因是第9行中的@Observes批注。僅此批注將使此方法在事件觸發后運行。

但是,我們只需要在提交事務 !時才觸發此事件。 回滾不應觸發電子郵件。 這就是“ during”屬性的來源。通過指定值TransactionPhase.AFTER_SUCCESS,我們確保僅在事務成功提交后才觸發事件。

最后但并非最不重要的一點是,我們還需要使此邏輯與主邏輯在單獨的線程中運行。 它必須異步運行。 為此,我們僅使用了兩個EJB批注@Asynchronous和@Lock(LockType.READ) 。 后者@Lock(LockType.READ)不是必需的,但強烈建議使用。 它保證不使用鎖,并且多個線程可以同時使用該方法。

在JBoss Wildfly 8.1.0中配置郵件會話

作為獎勵,我將展示如何在JBoss WildFly中正確配置郵件“源”。 郵件源與數據源非常相似,除了它們用于發送電子郵件而不是用于數據庫:)。 這是一種使代碼與如何建立與郵件服務器的連接脫鉤的方法。 我使用了與我的Gmail帳戶的連接,但是您無需切換MailService類中的任何代碼即可切換到所需的任何內容。

可以使用@Resource批注以其JNDI名稱檢索javax.mail.Session對象:

@Resource(mappedName = "java:jboss/mail/Gmail") private Session mailSession;

您可能已經注意到,在我以前的代碼片段中,我沒有使用@Resource批注,而僅使用了CDI的@Inject 。 好吧,如果您好奇我是怎么做到的,只需下載源代碼并看一下即可。 ( 提示:我使用了生產者幫助器類 。)

繼續,只需打開standalone.xml (如果處于域模式,則打開domain.xml),然后首先查找“郵件子系統”。 它看起來應該像這樣:

<subsystem xmlns="urn:jboss:domain:mail:2.0"><mail-session name="default" jndi-name="java:jboss/mail/Default"><smtp-server outbound-socket-binding-ref="mail-smtp"/></mail-session> </subsystem>

默認情況下,已經在本地主機上運行了一個已提供的郵件會話。 由于您的開發機器上可能沒有運行任何郵件服務器,因此我們將添加一個指向gmail的新郵件服務器:

<subsystem xmlns="urn:jboss:domain:mail:2.0"><mail-session name="default" jndi-name="java:jboss/mail/Default"><smtp-server outbound-socket-binding-ref="mail-smtp"/></mail-session><mail-session name="gmail" jndi-name="java:jboss/mail/Gmail" from="your.account@gmail.com"><smtp-server outbound-socket-binding-ref="mail-gmail" ssl="true" username="your.account@gmail.com" password="your-password"/></mail-session> </subsystem>

查看第5、6和7行如何突出顯示。 那是我們的新郵件會話。 但這還不是全部。 我們仍然需要創建一個套接字綁定到我們的新郵件會話。 因此,在standalone.xml內查找一個名為socket-binding-group的元素:

<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}"><!-- a bunch of stuff here --><outbound-socket-binding name="mail-smtp"><remote-destination host="localhost" port="25"/></outbound-socket-binding></socket-binding-group>

現在,通過創建新的outbound-socket-binding元素,將gmail端口添加到現有端口:

<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}"><!-- a bunch of stuff here --><outbound-socket-binding name="mail-smtp"><remote-destination host="localhost" port="25"/></outbound-socket-binding><!-- "mail-gmail" is the same name we used in the mail-session config --><outbound-socket-binding name="mail-gmail"><remote-destination host="smtp.gmail.com" port="465"/></outbound-socket-binding></socket-binding-group>

就是這個。 如果您有任何問題,請發表評論:)。 后來!

翻譯自: https://www.javacodegeeks.com/2015/03/cdi-ejb-sending-asynchronous-mail-on-transaction-success.html

php cdi

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的php cdi_CDI和EJB:在事务成功时发送异步邮件的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 日韩综合一区二区三区 | 国产强被迫伦姧在线观看无码 | 欧美国产在线视频 | 一级中文字幕 | 国产黄在线免费观看 | 日韩午夜影院 | 天堂资源 | 欧美一区二区三区不卡视频 | 亚洲激情av在线 | 日本免费电影一区二区三区 | 久久婷婷五月综合色国产香蕉 | 日韩欧美一区视频 | 四季av一区二区凹凸精品 | 欧美日本韩国一区 | 在线不卡日本 | 国产欧美色图 | 91亚洲精选 | 久久人人精品 | 国产哺乳奶水91在线播放 | 小向美奈子在线观看 | 亚洲国产欧美另类 | 午夜久久福利 | 成人精品一区二区三区四区 | 日韩有码在线观看 | 波多野结衣av电影 | 亚洲一卡二卡三卡 | 欧美另类色 | 正在播放欧美 | 亚洲欧美系列 | 黄色综合网站 | 在线观看免费视频国产 | 看av网址| 精品一区二区三区在线观看视频 | 国产精品一二 | 久久亚洲私人国产精品va | 久久69| 国产一区二区三区免费观看视频 | 精品国产丝袜一区二区三区乱码 | 国产乱码精品一区二三赶尸艳谈 | 波多野结衣av在线观看 | 久久五月视频 | 国产成人无码一区二区在线播放 | 性xxxx搡xxxxx搡欧美 | 亚洲天堂影视 | 国产精品一区麻豆 | 国产成人三级在线观看 | 中文字幕av网站 | 国产又粗又大又硬 | 成人试看120秒体验区 | 五月婷婷爱爱 | 日本不卡视频一区二区三区 | 精品人妻一区二区三区四区不卡 | 涩涩视频免费在线观看 | 一边吃奶一边摸做爽视频 | 五月婷婷基地 | 黄色小视频免费观看 | 国产精品爽爽爽 | www.av免费 | 啦啦啦视频在线观看 | 久久亚洲日本 | 91粉色视频 | 国产成人免费在线视频 | 聚色av| 在线观看午夜视频 | 亚洲欧美在线播放 | 亚洲AV午夜精品 | 欧美成人精品在线视频 | 午夜精品在线免费观看 | 无码av免费毛片一区二区 | 一级黄色av| 亚洲精品视频一区二区三区 | 亚洲欧洲精品一区二区三区 | 欧美精品一区二区三区久久 | 成年人黄色小视频 | 国产成人啪一区二区 | 91精品国产乱码久久久久 | 国产不卡一 | 俄罗斯美女一级爱片 | 亚洲日本欧美精品 | 草草久久久无码国产专区 | 巨乳女教师的诱惑 | 免费a级 | 欧美一区二区精品 | 色综合色综合网色综合 | 玖玖精品在线 | 久久99精品久久久久子伦 | 亚洲成人一区在线观看 | 97人妻一区二区精品视频 | 国产欧美日韩高清 | 亚洲影视一区二区 | 久草视频在线资源 | 亚洲精品大片www | 国模私拍一区二区 | 欧美极品aaaaabbbbb| 日韩成人精品一区二区三区 | 中文自拍 | 无码h黄肉3d动漫在线观看 | 网站一级片 | 日韩精品视频免费播放 |