2010-08-16 23 views
11

Belirli olayların meydana geldiği durumlarda daha geniş bir sistemi bilgilendirmek için hizmet uygulamamdaki Yay uygulama olaylarını kullanıyorum. Sahip olduğum sorun, olayların bir işlem bağlamında işlenmesidir (Spring'in @Transactional ek açıklamasını kullanıyorum). Tehlike, bir olayı tetiklemem ve daha sonra işlemin başarısızlığa uğramasıdır (örneğin, Hazırda Bekletme kullanılırken meydana gelebilir). Bu senaryoda, olay dinleyicileri, idam edildikten sonra geri alınacak bazı durumları üstlenecekler. Buradaki tehlike, örneğin, kullanıcı hesabının gerçekte oluşturulmadığı bir web sitesinde kullanıcı kaydını onaylamak için bir e-posta gönderdiğim.Yay İşlemi Ek Açıklamaları - Başarı ile Çalıştırın

Ek açıklamaların kullanımını koruyan bir yol var mı? İşlemin yapılmasının ardından bir olayın tetikleneceği bir yere işaret mi edilmeli? Java Swing'de GUI programlama yaparken SwingUtilities.invokeLater(Runnable runnable)'u kullanmaya benziyor. Mevcut işlem başarıyla tamamlandığında, bu kodu biraz sonra yürütmek istiyorum.

Herhangi bir fikrin var mı?

sayesinde

Andrew

+0

Bu, tüm ek açıklamalar aracılığıyla artık ilkbaharda doğal ele olduğunu. https://spring.io/blog/2015/02/11/better-application-events-in-spring-framework-4-2https://spring.io/blog/2015/02/11/better adresine bakın. -pencerede-yayında-çerçeve-4-2 özellikle yeni @TransactionalEventListener ek açıklaması hakkında bölüm. – PaulNUK

cevap

2

onay e-postalar ile sorunu çözmek için uygun yolu onlara katılan JMS kaynakla bir dağıtılmış işlemler kullanmak üzere muhtemelen.

Ancak, kirli hızlı ve-çözüm olarak, size taahhüt başarılı sonra biraz ThreadLocal depolama kayıtlı Runnable s çalıştırır bir PlatformTransactionManager etrafında sarıcı oluşturmaya çalışabilir (ve geri alma sonra ThreadLocal çıkarın). Aslında, AbstractPlatformTransactionManager, TransactionSynchronization s ile tam olarak bu tür bir mantığa sahiptir, ancak uygulama ayrıntılarının çok derinlerine gömülüdür.

+0

Şimdilik hızlı ve kirli çözümle gittim. Bir TransactionStatus nesnesiyle Runnable nesnelerinin bir sırasını ilişkilendiren ThreadLocal tabanlı bir mekanizma kurdum. Bir TransactionStatus'un commit() veya rollback() 'ı üzerinde Runnable nesnelerini çalıştırır veya atarım. Oldukça güzel çalışıyor. – DrewEaster

+0

Bir kod snippet'i verebilir misiniz? – Oliv

+0

Dağıtılmış işlemlerin doğru _proper_ çözümü olduğunu söylemem. Dağıtılan işlem, yalnızca posta gönderilirse tüm işlem başarısız olur. Ancak burada istenen davranış, postaların DB işlemine bağlı olması ve DB işleminin postaya bağlı olmamasıdır. – yair

4

PlatformTransactionManager'ı kesmeye gerek kalmadan TransactionSynchronizationManager'ı kullanabilirsiniz.

Not: TransactionAware, bir ApplicationListener işlem başarılı bir şekilde işlendikten sonra bir Event almak istediğini belirten bir işaretçi arabirimidir.

public class TransactionAwareApplicationEventMulticaster extends SimpleApplicationEventMulticaster { 

    @Override 
    public void multicastEvent(ApplicationEvent event) { 
     for (ApplicationListener listener : getApplicationListeners(event)) { 
      if ((listener instanceof TransactionAware) && TransactionSynchronizationManager.isSynchronizationActive()) { 
       TransactionSynchronizationManager.registerSynchronization(
        new EventTransactionSynchronization(listener, event)); 
      } 
      else { 
       notifyEvent(listener, event); 
      } 
     } 
    } 

    void notifyEvent(final ApplicationListener listener, final ApplicationEvent event) { 
      Executor executor = getTaskExecutor(); 
      if (executor != null) { 
       executor.execute(new Runnable() { 
        public void run() { 
         listener.onApplicationEvent(event); 
        } 
       }); 
      } 
      else { 
       listener.onApplicationEvent(event); 
      } 
    } 

    class EventTransactionSynchronization extends TransactionSynchronizationAdapter { 
     private final ApplicationListener listener; 
     private final ApplicationEvent event; 

     EventTransactionSynchronization(ApplicationListener listener, ApplicationEvent event) { 
      this.listener = listener; 
      this.event = event; 
     } 

     @Override 
     public void afterCompletion(int status) { 
      if ((phase == TransactionPhase.AFTER_SUCCESS) 
        && (status == TransactionSynchronization.STATUS_COMMITTED)) { 
       notifyEvent(listener, event); 
      } 
     } 
    } 
} 
10

Bu benim için çalışıyor:

TransactionSynchronizationManager.registerSynchronization(
    new TransactionSynchronizationAdapter() { 
     @Override 
     public void afterCommit() { 
      // things to do when commited 
     } 
     // other methods to override are available too 
    }); 
+0

Güzel! IMO ile ilgili olarak en iyi cevap. Bu en çok SwingUtilities.invokeLater'a benzer. –