2012-07-23 6 views
11

मूल प्रश्न का सारांश: एओपी प्रॉक्सीइंग के साथ मानक वसंत लेनदेन का उपयोग करना, गैर[email protected] लेनदेन-संबंधी से एक @ लेनदेन-चिह्नित विधि को कॉल करना संभव नहीं है। एक ही कक्षा में चिह्नित विधि और एक लेनदेन के भीतर हो (विशेष रूप से उपर्युक्त प्रॉक्सी के कारण)। यह AspectJ मोड में वसंत लेनदेन के साथ माना जाता है, लेकिन यह कैसे किया जाता है?पुराना "@ उसी श्रेणी के भीतर से ट्रान्ससेक्शन" स्थिति

संपादित करें: का उपयोग कर लोड समय बुनाई AspectJ मोड में वसंत लेन-देन के लिए पूर्ण ठहरनेवाला:

जोड़े निम्नलिखित META-INF/spring/applicationContext.xml रहे हैं:

<tx:annotation-driven mode="aspectj" /> 

<context:load-time-weaver /> 

(मैं तुम्हें मान लेंगे पहले से ही है एक AnnotationSessionFactoryBean और HibernateTransactionManager एप्लिकेशन संदर्भ में स्थापित है। आप अपने <tx:annotation-driven /> टैग पर एक विशेषता के रूप में transaction-manager="transactionManager" जोड़ सकते हैं, लेकिन यदि आपके लेनदेन प्रबंधक का मूल्य बीन 0 हैविशेषता वास्तव में है "transactionManager", तो यह बेमानी है, के रूप में "transactionManager" उस गुण के डिफ़ॉल्ट मान है।)

META-INF/aop.xml जोड़ें।

<aspectj> 
    <aspects> 
    <aspect name="org.springframework.transaction.aspectj.AnnotationTransactionAspect" /> 
    </aspects> 
    <weaver> 
    <include within="my.package..*" /><!--Whatever your package space is.--> 
    </weaver> 
</aspectj> 

अपने classpath करने के लिए aspectjweaver-1.7.0.jar और spring-aspects-3.1.2.RELEASE.jar जोड़ें: सामग्री इस प्रकार हैं। मैं अपने निर्माण उपकरण के रूप में Maven का उपयोग, इसलिए यहाँ हैं अपने प्रोजेक्ट की POM.xml फ़ाइल के लिए <dependency /> घोषणाओं:

<dependency> 
    <groupId>org.aspectj</groupId> 
    <artifactId>aspectjweaver</artifactId> 
    <version>1.7.0</version> 
</dependency> 
<dependency> 
    <groupId>org.springframework</groupId> 
    <artifactId>spring-aspects</artifactId> 
    <version>3.1.2.RELEASE</version> 
</dependency> 

spring-instrument-3.1.2.RELEASE.jar अपने classpath पर एक <dependency /> के रूप में की जरूरत नहीं है, लेकिन आप अभी भी यह कहीं तो आप कर सकते हैं कि जरूरत -javaagent JVM ध्वज के साथ इस पर बात, इस प्रकार है:

-javaagent:full\path\of\spring-instrument-3.1.2.RELEASE.jar 

मैं ग्रहण जूनो में काम कर रहा हूँ, तो यह मैं खिड़की के पास गया स्थापित करने के लिए -> वरीयताएँ -> जावा -> स्थापित JREs। फिर मैंने सूची बॉक्स में चेक किए गए जेआरई पर क्लिक किया और सूची बॉक्स के दाईं ओर "संपादित करें ..." बटन पर क्लिक किया। परिणामी पॉपअप विंडो में तीसरा टेक्स्ट बॉक्स "डिफ़ॉल्ट वीएम तर्क:" लेबल किया गया है। यह वह जगह है जहां -javaagent ध्वज टाइप किया जाना चाहिए या कॉपी + पेस्ट किया जाना चाहिए।

अब मेरे वास्तविक परीक्षण कोड कक्षाओं के लिए। सबसे पहले, अपने मुख्य वर्ग, TestMain.java:

package my.package; 

import org.springframework.context.ApplicationContext; 
import org.springframework.context.support.ClassPathXmlApplicationContext; 

public class TestMain { 
    public static void main(String[] args) { 
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("META-INF/spring/applicationContext.xml"); 
    TestClass testClass = applicationContext.getBean(TestClass.class); 
    testClass.nonTransactionalMethod(); 
    } 
} 

और फिर मेरे व्यवहार वर्ग, TestClass.java:

package my.package; 

import my.package.TestDao; 
import my.package.TestObject; 
import org.springframework.transaction.annotation.Transactional; 

public void TestClass { 
    private TestDao testDao; 

    public void setTestDao(TestDao testDao) { 
    this.testDao = testDao; 
    } 

    public TestDao getTestDao() { 
    return testDao; 
    } 

    public void nonTransactionalMethod() { 
    transactionalMethod(); 
    } 

    @Transactional 
    private void transactionalMethod() { 
    TestObject testObject = new TestObject(); 
    testObject.setId(1L); 
    testDao.save(testObject); 
    } 
} 

चाल यहाँ है कि अगर TestClassTestMain में एक क्षेत्र है अपने वर्ग द्वारा लोड किया जाएगा आवेदन संदर्भ लोड होने से पहले ClassLoader। चूंकि बुनाई कक्षा के लोड-टाइम पर है, और यह बुनाई स्प्रिंग द्वारा एप्लिकेशन संदर्भ के माध्यम से की जाती है, इसलिए यह बुना नहीं जाएगा क्योंकि आवेदन संदर्भ लोड होने से पहले कक्षा पहले ही लोड हो चुकी है और इसके बारे में पता है।

TestObject और TestDao के आगे के विवरण महत्वहीन हैं।मान लें कि वे जेपीए और हाइबरनेट एनोटेशन के साथ वायर्ड हैं और दृढ़ता के लिए हाइबरनेट का उपयोग करते हैं (क्योंकि वे हैं, और वे करते हैं), और सभी आवश्यक <bean /> एप्लिकेशन संदर्भ फ़ाइल में स्थापित हैं।

संपादित करें: का उपयोग कर संकलन समय बुनाई AspectJ मोड में वसंत लेन-देन के लिए पूर्ण ठहरनेवाला:

जोड़े निम्नलिखित META-INF/spring/applicationContext.xml रहे हैं:

<tx:annotation-driven mode="aspectj" /> 

(मैं तुम्हें मान लेंगे पहले से ही है एक AnnotationSessionFactoryBean और HibernateTransactionManager एप्लिकेशन संदर्भ में स्थापित है। आप अपने <tx:annotation-driven /> टैग पर एक विशेषता के रूप में transaction-manager="transactionManager" जोड़ सकते हैं, लेकिन यदि आपके लेनदेन प्रबंधक का मूल्य सेम के id विशेषता वास्तव में है "transactionManager", तो यह बेमानी है, के रूप में "transactionManager" उस गुण के डिफ़ॉल्ट मान है।)

अपने classpath करने के लिए spring-aspects-3.1.2.RELEASE.jar और aspectjrt-1.7.0.jar जोड़ें। मैं अपने निर्माण उपकरण के रूप में Maven का उपयोग करें, तो यहां POM.xml फ़ाइल के लिए <dependency /> घोषणाओं है:

<dependency> 
    <groupId>org.springframework</groupId> 
    <artifactId>spring-aspects</artifactId> 
    <version>3.1.2.RELEASE</version> 
</dependency> 
<dependency> 
    <groupId>org.aspectj</groupId> 
    <artifactId>aspectjrt</artifactId> 
    <version>1.7.0</version> 
</dependency> 

ग्रहण जूनो में: सहायता -> ग्रहण बाज़ार -> पाठ बॉक्स लेबल "खोजें:" -> प्रकार "ajdt" - > हिट [एंटर] -> "AspectJ विकास उपकरण (जूनो)" -> इंस्टॉल करें -> आदि

ग्रहण को पुनरारंभ करने के बाद (यह आपको बनाएगा), संदर्भ मेनू लाने के लिए अपनी प्रोजेक्ट पर राइट-क्लिक करें। नीचे के नजदीक देखें: कॉन्फ़िगर करें -> AspectJ प्रोजेक्ट में कनवर्ट करें।

(फिर Maven के साथ!) अपने POM.xml में निम्नलिखित <plugin /> घोषणा जोड़ें:

<plugin> 
    <groupId>org.codehaus.mojo</groupId> 
    <artifactId>aspectj-maven-plugin</artifactId> 
    <version>1.4</version> 
    <configuration> 
    <aspectLibraries> 
     <aspectLibrary> 
     <groupId>org.springframework</groupId> 
     <artifactId>spring-aspects</artifactId> 
     </aspectLibrary> 
    </aspectLibraries> 
    </configuration> 
    <executions> 
    <execution> 
     <goals> 
     <goal>compile</goal> 
     <goal>test-compile</goal> 
     </goals> 
    </execution> 
    </executions> 
</plugin> 

वैकल्पिक: संदर्भ मेनू ऊपर लाने के लिए अपनी परियोजना पर राइट क्लिक करें। नीचे के नजदीक देखें: AspectJ टूल्स -> AspectJ बिल्ड पथ कॉन्फ़िगर करें -> पहलू पथ टैब -> "बाहरी जार जोड़ें ..." दबाएं ->full/path/of/spring-aspects-3.1.2.RELEASE.jar का पता लगाएं -> "ओपन" दबाएं -> "ठीक" दबाएं।

यदि आप मेवेन मार्ग लेते हैं, तो <plugin /> उपरोक्त होना चाहिए। इसे ठीक करने के लिए: सहायता -> नया सॉफ़्टवेयर इंस्टॉल करें ... -> "जोड़ें ..." दबाएं -> "नाम:" लेबल वाले टेक्स्ट बॉक्स में जो कुछ भी आपको पसंद है, टाइप करें या कॉपी करें + पेस्ट http://dist.springsource.org/release/AJDT/configurator/ लेबल वाले टेक्स्ट बॉक्स में टाइप करें "स्थान:" -> "ओके" दबाएं -> एक सेकंड प्रतीक्षा करें -> ग्रहण एजेडीटी एकीकरण के लिए "मैवेन इंटीग्रेशन" के आगे अभिभावक चेकबॉक्स को चेक करें -> "अगला>" -> इंस्टॉल करें -> आदि

कब प्लगइन स्थापित है, और आपने एक्लिप्स को पुनरारंभ किया है, आपकी POM.xml फ़ाइल में त्रुटियां दूर होनी चाहिए थीं। यदि नहीं, तो संदर्भ मेनू लाने के लिए अपनी प्रोजेक्ट पर राइट-क्लिक करें: मेवेन -> अपडेट प्रोजेक्ट -> "ठीक" दबाएं।

अब मेरे वास्तविक परीक्षण कोड वर्ग के लिए। केवल एक ही इस बार, TestClass.java:

package my.package; 

import my.package.TestDao; 
import my.package.TestObject; 
import org.springframework.context.ApplicationContext; 
import org.springframework.context.support.ClassPathXmlApplicationContext; 
import org.springframework.transaction.annotation.Transactional; 

public void TestClass { 
    private TestDao testDao; 

    public void setTestDao(TestDao testDao) { 
    this.testDao = testDao; 
    } 

    public TestDao getTestDao() { 
    return testDao; 
    } 

    public static void main(String[] args) { 
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("META-INF/spring/applicationContext.xml"); 
    TestClass testClass = applicationContext.getBean(TestClass.class); 
    testClass.nonTransactionalMethod(); 
    } 

    public void nonTransactionalMethod() { 
    transactionalMethod(); 
    } 

    @Transactional 
    private void transactionalMethod() { 
    TestObject testObject = new TestObject(); 
    testObject.setId(1L); 
    testDao.save(testObject); 
    } 
} 

यह एक करने के लिए कोई चाल नहीं है; चूंकि बुनाई संकलन समय पर होती है, जो क्लास लोडिंग और एप्लिकेशन संदर्भ लोडिंग दोनों से पहले होती है, इन दो चीजों का क्रम अब महत्वपूर्ण नहीं है। इसका मतलब है कि सब कुछ एक ही कक्षा में जा सकता है। ग्रहण में, जब भी आप सहेजते हैं, तब भी आपका कोड फिर से संकलित किया जा रहा है (कभी भी आश्चर्य हुआ कि यह कह रहा था कि "बिल्डिंग वर्कस्पेस: (एक्सएक्स%)"?), इसलिए यह बुना हुआ है और जब भी आप जाने के लिए तैयार हैं।

बस लोड-टाइम उदाहरण की तरह: TestObject और TestDao के आगे के विवरण महत्वहीन हैं। मान लें कि वे जेपीए और हाइबरनेट एनोटेशन के साथ वायर्ड हैं और दृढ़ता के लिए हाइबरनेट का उपयोग करते हैं (क्योंकि वे हैं, और वे करते हैं), और सभी आवश्यक <bean /> एप्लिकेशन संदर्भ फ़ाइल में स्थापित हैं।

+0

बस यह सुनिश्चित करने के लिए - मुझे लगता है कि आपके पास लेनदेन है, हाइबरनेट सत्र में लपेटकर प्रबंधक परिभाषित किया गया है फैक्टरी: org.springframework.orm.hibernate3.HibernateTransactionManager। इसके अलावा, क्या आप अपने टेस्टडाओ के भीतर कार्यान्वयन दिखा सकते हैं।क्या आप आगे यह पुष्टि कर सकते हैं कि जब आप सीधे @ ट्रांस्सेक्शन परीक्षण के भीतर 'लेनदेन विधि' को कॉल करते हैं, तो क्या यह सही तरीके से काम करता है और समस्या तब होती है जब आप 'test' विधि से कॉल करते हैं? –

+0

क्या इस तरह से ऑब्जेक्ट को इंजेक्ट करने के लिए एक रास्ता होगा, और उसके बाद इंजेक्शन संदर्भ पर विधि को कॉल करें, उम्मीद है कि प्रॉक्सी इंजेक्शन दिया गया था? –

उत्तर

9

अपना प्रश्न पढ़कर यह वास्तव में स्पष्ट नहीं है कि आप कहां फंस गए हैं, इसलिए मैं संक्षेप में सूचीबद्ध हूं कि AspectJ आपके @Transactional विधियों को रोकता है।

  1. <tx:annotation-driven mode="aspectj"/> आपकी स्प्रिंग कॉन्फ़िगरेशन फ़ाइल में।
  2. <context:load-time-weaver/> साथ ही साथ आपकी स्प्रिंग कॉन्फ़िगरेशन फ़ाइल में भी।
  3. एक aop.xml सीधे आपके क्लासपाथ में मेटा-आईएनएफ फ़ोल्डर में स्थित है। इसका प्रारूप भी here समझाया गया है। यह एक पहलू परिभाषा होनी चाहिए कि @Transactional एनोटेशन संभालती के लिए: <include within="foo.*"/>
  4. aspectjrt.jar, aspectjweaver.jar, spring-aspects.jar और spring-aop.jar में: <aspect name="org.springframework.transaction.aspectj.AnnotationTransactionAspect"/>
  5. कि एक ही फाइल में बुनकर तत्व भी एक खंड है कि कहता है जो कक्षाओं बुनाई करना शामिल होना चाहिए classpath
  6. (या वसंत-एजेंट के रूप में यह पहले के रिलीज में कहा जाता है) झंडा -javaagent:/path/to/spring-instrument.jar का उपयोग कर आवेदन शुरू

अंतिम चरण आवश्यक नहीं हो सकता। यह वास्तव में एक साधारण वर्ग है जो InstrumentationLoadTimeWeaver का उपयोग करने में सक्षम बनाता है, लेकिन यदि उपलब्ध नहीं है तो वसंत एक और लोड टाइम वीवर का उपयोग करने का प्रयास करेगा। मैंने कभी कोशिश नहीं की है, यद्यपि।

अब

, अगर आपको लगता है आप सभी चरणों को पूरा किया है और अभी भी समस्या हो रही है, मैं बुनकर पर कुछ विकल्प को सक्षम सिफारिश कर सकते हैं (aop.xml में परिभाषित):

<weaver options="-XnoInline -Xreweavable -verbose -debug -showWeaveInfo"> 

यह बुनकर उत्पादन एक बनाता है बुनाई जा रही जानकारी का गुच्छा। यदि आप कक्षाओं को बुनाई देखते हैं, तो आप वहां अपने देख सकते हैं। फिर कम से कम समस्या निवारण जारी रखने के लिए एक प्रारंभिक बिंदु है।


अपने दूसरे संपादित करें, के बारे में "यह लगभग की तरह बुनाई काफी तेजी से नहीं हो रहा है से पहले वर्ग पर अमल करने की कोशिश करता है बुना जा करने के लिए है।", जवाब हाँ, ऐसा हो सकता है। I experienced a situation like this before

मैं विनिर्देशों पर थोड़ा सा जंगली हूं, लेकिन मूल रूप से यह कुछ पंक्तियों में है कि स्प्रिंग उन अनुप्रयोगों को बुनाई करने में सक्षम नहीं होगी जो अनुप्रयोग संदर्भ बनाने से पहले लोड किए गए हैं। आप अपना आवेदन संदर्भ कैसे बना रहे हैं? यदि आप इसे प्रोग्रामिक रूप से कर रहे हैं, और उस वर्ग का का प्रत्यक्ष संदर्भ है, तो यह समस्या हो सकती है, क्योंकि बहुत जल्दी लोड हो जाएगा।

दुर्भाग्यवश, मुझे पता चला है कि डिस्गिंग AspectJ नरक है।

+0

यह लोड-टाइम बुनाई के लिए सब कुछ है। क्या आप यह कहने की कोशिश कर रहे हैं कि AspectJ मोड में वसंत लेनदेन ('') लोड-टाइम बुनाई का उपयोग कर केवल संभव है? क्योंकि, यदि हां, तो पूरी बात भूल जाओ, क्योंकि मैंने कुछ हद तक '-जावाजेंट' सामान के साथ प्रयोग किया था और मैं ऐसे माहौल में नहीं हूं जहां मैं जेवीएम झंडे डाल सकता हूं। –

+0

इसके अलावा: आप चरण 5 में 'वसंत-पहलू .jar' भूल गए हैं, क्योंकि मुझे क्लास नॉटफाउंड अपवाद प्राप्त हो रहा है: "org.springframework.transaction.aspectj.AnnotationTransactionAspect" –

+0

मैंने वसंत-पहलुओं में संपादित किया। आपकी दूसरी टिप्पणी के लिए, अच्छी तरह से, संकलन-समय बुनाई पूरी तरह से अलग जानवर है। उम्मीद है कि कोई और जवाब दे सकता है जिसके लिए आवश्यक है। ध्यान दें कि जेवीएम झंडे के बिना लोड-टाइम बुनाई संभव हो सकती है (आपके पर्यावरण के आधार पर): http://static.springsource.org/spring/docs/3.0.x/reference/aop.html में तालिका 7.1 देखें – waxwing

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