मूल प्रश्न का सारांश: एओपी प्रॉक्सीइंग के साथ मानक वसंत लेनदेन का उपयोग करना, गैर[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);
}
}
चाल यहाँ है कि अगर TestClass
TestMain
में एक क्षेत्र है अपने वर्ग द्वारा लोड किया जाएगा आवेदन संदर्भ लोड होने से पहले 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 />
एप्लिकेशन संदर्भ फ़ाइल में स्थापित हैं।
बस यह सुनिश्चित करने के लिए - मुझे लगता है कि आपके पास लेनदेन है, हाइबरनेट सत्र में लपेटकर प्रबंधक परिभाषित किया गया है फैक्टरी: org.springframework.orm.hibernate3.HibernateTransactionManager। इसके अलावा, क्या आप अपने टेस्टडाओ के भीतर कार्यान्वयन दिखा सकते हैं।क्या आप आगे यह पुष्टि कर सकते हैं कि जब आप सीधे @ ट्रांस्सेक्शन परीक्षण के भीतर 'लेनदेन विधि' को कॉल करते हैं, तो क्या यह सही तरीके से काम करता है और समस्या तब होती है जब आप 'test' विधि से कॉल करते हैं? –
क्या इस तरह से ऑब्जेक्ट को इंजेक्ट करने के लिए एक रास्ता होगा, और उसके बाद इंजेक्शन संदर्भ पर विधि को कॉल करें, उम्मीद है कि प्रॉक्सी इंजेक्शन दिया गया था? –