2011-03-18 18 views
10

मेरे पास एक springframework एप्लिकेशन है जिसमें मैं एक लेनदेन श्रोता को एक लेनदेन में जोड़ना चाहता हूं जो वर्तमान में प्रगति पर है। प्रेरणा एक पोस्ट प्रतिबद्ध कार्रवाई को ट्रिगर करना है जो डाउनस्ट्रीम सिस्टम को सूचित करती है। मैं कुछ सेवा विधि के आसपास एक लेनदेन लपेटने के लिए @ ट्रांसेक्शनल का उपयोग कर रहा हूं - जहां मैं पोस्ट लेनदेन श्रोता बनाने/पंजीकृत करना चाहता हूं। मैं निम्नलिखित "जैसे" कुछ करना चाहता हूं।गतिशील रूप से वसंत के साथ लेनदेन श्रोता पंजीकृत करें?

public class MyService { 
@Transaction 
public void doIt() { 
    modifyObjects(); 

    // something like this 
    getTransactionManager().registerPostCommitAction(new 
    TransactionSynchronizationAdapter() { 
    public void afterCommit() { 
     notifyDownstream(); 
    } 
    }); 
} 
} 

स्प्रिंग एक TransactionSynchronization इंटरफेस और अनुकूलक वर्ग लगती है जो मैं वास्तव में क्या चाहते हैं; हालांकि यह तुरंत स्पष्ट नहीं है कि वर्तमान लेनदेन, या लेनदेन प्रबंधक के साथ गतिशील रूप से पंजीकरण कैसे करें। यदि मैं इससे बच सकता हूं तो मैं JtaTransactionManager को उपclass नहीं करना चाहूंगा।

प्रश्न: क्या किसी ने इससे पहले किया है।

प्रश्न: मेरे एडाप्टर को पंजीकृत करने का सबसे आसान तरीका क्या है?

उत्तर

3

आप अपनी सेवा में एक aspect to match व्यवहार तरीकों पहलू इस्तेमाल कर सकते हैं यह पूरा करने के:

@Aspect 
public class AfterReturningExample { 

    @AfterReturning("execution(* com.mypackage.MyService.*(..))") 
    public void afterReturning() { 
    // ... 
    } 

} 
+0

हालांकि, कोई अच्छा सुझाव किसी लेनदेन में निष्पादित नहीं होगा? मैं केवल सफल पूरा करना चाहता हूँ। साथ ही, क्या मैं उन एओपी एनोटेशन का उपयोग डिफ़ॉल्ट वसंत (मैं कोड बुनाई का उपयोग नहीं कर रहा हूं) बस जेडीके प्रॉक्सी के साथ कर सकता हूं। – Justin

+0

विधियों को अपवाद फेंकने पर रिटर्न सलाह नहीं चलती है, इसलिए जब यह विधि परिणाम देता है और अपवाद फेंकते समय वापस रोलिंग करता है तो यह रिटर्नशिपल पर निर्भर करता है, जो आम तौर पर होता है। पहलुओं को स्प्रिंग्स गतिशील प्रॉक्सी के माध्यम से बुलाया जाता है, इसलिए यह कोई भी कोड बुनाई नहीं करता है (जब तक कि आप वसंत के लिए इंटरफेस प्रदान नहीं करते हैं, जहां वसंत सीजीएलआईबी के साथ रनटाइम पर कोड बुनाई में वापस आ जाएगा)। दिलचस्प के लिए – krock

+1

+1, लेकिन मैं अभी भी परीक्षण के बिना आश्वस्त नहीं हूँ। कम से कम 2 @AfterReturning शामिल हैं: @ ट्रांसेक्शनल और फिर मेरा कस्टम पहलू। यदि @ ट्रान्ससेनल रन चलता है, तो मेरा रन चलता है सब ठीक है; हालांकि दूसरे आदेश में मैं लेनदेन प्रतिबद्धता की स्थिति से स्वतंत्र रूप से निष्पादित करूंगा। एक अच्छा और सीधा जवाब के लिए – Justin

26

वास्तव में यह रूप में मुश्किल के रूप में मैंने सोचा था कि नहीं था, वसंत में एक स्थिर सहायक वर्ग होता है जो 'दाएं' सामान को थ्रेड संदर्भ में रखता है।

TransactionSynchronizationManager.registerSynchronization(
    new TransactionSynchronizationAdapter() { 
     @Override 
     public void afterCommit() { 
      s_logger.info("TRANSACTION COMPLETE!!!"); 
     } 
    } 
); 
+0

+1। मुझे नहीं पता था कि लेनदेन सिंक्रनाइज़ेशन प्रबंधक मौजूद था। – krock

+0

असल में यह समाधान उतना अच्छा नहीं है जितना कि मैंने किया था। TransactionSynchronizationManager के लिए अनुबंध अधिक व्यापक है, और बाद में कोड() कोई अपवाद नहीं) के भीतर से एक जेएमएस संदेश भेजने की कोशिश कर रहा है क्योंकि उपरोक्त कोड अनुबंध का पालन करता है। – Justin

+0

अधिकांश स्प्रिंग मैसेजिंग समाधान (जेएमएस, एएमक्यूपी) आपको अपने लेनदेन प्रबंधक में प्लग इन करने की अनुमति देते हैं ताकि दोनों सिस्टम (डीबी, संदेश ब्रोकर) के बीच लेनदेन सिंक्रनाइज़ हो जाएं। मैं ऐसा नहीं करना चाहता था क्योंकि RabbitMQ TX बहुत धीमी है। नतीजतन आप मेरे समाधान को देखना चाह सकते हैं। –

2

यहाँ एक अधिक पूर्ण समाधान मैं एक ऐसी ही समस्या के लिए किया था कि मेरे संदेश के बाद लेन-देन के लिए प्रतिबद्ध हैं भेजा चाहने के साथ (मैं RabbitMQ TX इस्तेमाल किया जा सकता था, लेकिन वे नहीं बल्कि धीमी गति से कर रहे हैं) है।

public class MessageBusUtils { 
    public static Optional<MessageBusResourceHolder> getTransactionalResourceHolder(TxMessageBus messageBus) { 

     if (! TransactionSynchronizationManager.isActualTransactionActive()) { 
      return Optional.absent(); 
     } 

     MessageBusResourceHolder o = (MessageBusResourceHolder) TransactionSynchronizationManager.getResource(messageBus); 
     if (o != null) return Optional.of(o); 

     o = new MessageBusResourceHolder(); 
     TransactionSynchronizationManager.bindResource(messageBus, o); 
     o.setSynchronizedWithTransaction(true); 
     if (TransactionSynchronizationManager.isSynchronizationActive()) { 
      TransactionSynchronizationManager.registerSynchronization(new MessageBusResourceSynchronization(o, messageBus)); 
     } 
     return Optional.of(o); 

    } 

    private static class MessageBusResourceSynchronization extends ResourceHolderSynchronization<MessageBusResourceHolder, TxMessageBus> { 
     private final TxMessageBus messageBus; 
     private final MessageBusResourceHolder holder; 

     public MessageBusResourceSynchronization(MessageBusResourceHolder resourceHolder, TxMessageBus resourceKey) { 
      super(resourceHolder, resourceKey); 
      this.messageBus = resourceKey; 
      this.holder = resourceHolder; 
     } 


     @Override 
     protected void cleanupResource(MessageBusResourceHolder resourceHolder, TxMessageBus resourceKey, 
       boolean committed) { 
      resourceHolder.getPendingMessages().clear(); 
     } 

     @Override 
     public void afterCompletion(int status) { 
      if (status == TransactionSynchronization.STATUS_COMMITTED) { 
       for (Object o : holder.getPendingMessages()) { 
        messageBus.post(o, false); 
       } 
      } 
      else { 
       holder.getPendingMessages().clear(); 
      } 
      super.afterCompletion(status); 
     } 


    } 
} 

public class MessageBusResourceHolder extends ResourceHolderSupport { 

    private List<Object> pendingMessages = Lists.newArrayList(); 

    public void addMessage(Object message) { 
     pendingMessages.add(message); 
    } 


    protected List<Object> getPendingMessages() { 
     return pendingMessages; 
    } 

} 
अपनी कक्षा में अब

जहां आप वास्तव में संदेश आप

@Override 
public void postAfterCommit(Object o) { 
    Optional<MessageBusResourceHolder> holder = MessageBusTxUtils.getTransactionalResourceHolder(this); 
    if (holder.isPresent()) { 
     holder.get().addMessage(o); 
    } 
    else { 
     post(o, false); 
    } 
} 

घना कोडिंग नमूनों के लिए क्षमा करें, लेकिन उम्मीद है कि किसी को एक प्रतिबद्ध के बाद कुछ करने के लिए कैसे दिखा देंगे क्या करेंगे भेजें।

+0

लेनदेन के बाद मैं 3 सोलर इंडेक्स अपडेट करने के लिए अपना कोड उपयोग कर रहा हूं। मैं बिजनेस ऑब्जेक्ट्स में संशोधन का पता लगाने के लिए स्प्रिंग इवेंट का उपयोग कर रहा हूं, रिसोर्सहोल्डर में स्टोर स्टोर करता हूं, और इंडेक्स अपडेट करता हूं जिसे अतुल्यकालिक रूप से अद्यतन करने की आवश्यकता होती है। –

0

क्या प्रतिबद्धता और रोलबैक विधियों पर लेनदेन प्रबंधक को ओवरराइड करना समझ में आता है, शुरुआत में super.commit() पर कॉल करना।

संबंधित मुद्दे