के भीतर जेडीके और सीजीएलबीबी प्रॉक्सी मिश्रण करना मेरे पास स्प्रिंग के साथ चल रहा एक एप्लीकेशन है, और मैं कुछ स्थानों पर एओपी का उपयोग कर रहा हूं। चूंकि मैं इंटरफ़ेस स्तर पर @ ट्रांसेक्शनल एनोटेशन का उपयोग करना चाहता हूं, इसलिए मुझे वसंत को जेडीके प्रॉक्सी बनाने की अनुमति है। इसलिए, मैं प्रॉक्सी-लक्ष्य-श्रेणी संपत्ति को सत्य पर सेट नहीं करता हूं। दूसरी तरफ, मैं सलाह देने के लिए हर एक वर्ग के लिए एक इंटरफेस नहीं बनाना चाहता हूं: अगर इंटरफ़ेस सिर्फ समझ में नहीं आता है, तो मैं केवल कार्यान्वयन करना चाहता हूं, और वसंत को एक CGLIB प्रॉक्सी बनाना चाहिए।स्प्रिंग
सबकुछ ठीक से काम कर रहा था, जैसा मैंने वर्णन किया था। लेकिन मैं कुछ अन्य टिप्पणियां (मेरे द्वारा बनाई गई) इंटरफेस में जा रहा था और कार्यान्वयन वर्गों द्वारा "विरासत" प्राप्त करना चाहता था (जैसे @ ट्रान्सएक्शनल एक)। यह पता चला है कि मैं वसंत में एओपी के लिए अंतर्निहित समर्थन के साथ ऐसा नहीं कर सकता (कम से कम मैं इसे समझ नहीं पाया कि कुछ शोध के बाद इसे कैसे किया जाए। इंटरफ़ेस में एनोटेशन कार्यान्वयन कक्षा में दिखाई नहीं दे रहा है, और इसलिए उस वर्ग को सलाह नहीं दी जाती है)।
तो मैं अपने ही pointcut और इंटरसेप्टर लागू करने के लिए, अन्य विधि एनोटेशन इंटरफेस पर जाने के लिए अनुमति का फैसला किया। असल में, मेरा पॉइंटकट विधि पर एनोटेशन की तलाश करता है और जब तक कि क्लास या उसके सुपरक्लास लागू नहीं होता है, उसी इंटरफेस के समान विधि (समान नाम और पैरामीटर प्रकार) में नहीं मिला।
समस्या यह है: जब मैं एक डिफ़ॉल्ट एडवाइज़रऑटोप्रोक्सी क्रिएटर बीन घोषित करता हूं, जो इस पॉइंटकट/इंटरसेप्टर को उचित रूप से लागू करेगा, बिना किसी इंटरफेस वाले कक्षाओं को सलाह देने का व्यवहार टूटा हुआ है। स्पष्ट रूप से कुछ गलत हो जाता है और वसंत मेरी कक्षाओं को दो बार प्रॉक्सी करने की कोशिश करता है, एक बार CGLIB के साथ और फिर जेडीके के साथ।
@Component
public class ServiceExecutorImpl
{
@Transactional
public Object execute(...)
{
...
}
}
जब मैं इसे किसी और सेम में autowire करने की कोशिश:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd">
<!-- Activates various annotations to be detected in bean classes: Spring's
@Required and @Autowired, as well as JSR 250's @Resource. -->
<context:annotation-config />
<context:component-scan base-package="mypackage" />
<!-- Instruct Spring to perform declarative transaction management automatically
on annotated classes. -->
<tx:annotation-driven transaction-manager="transactionManager" />
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />
<bean id="logger.advisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<constructor-arg>
<bean class="mypackage.MethodAnnotationPointcut">
<constructor-arg value="mypackage.Trace" />
</bean>
</constructor-arg>
<constructor-arg>
<bean class="mypackage.TraceInterceptor" />
</constructor-arg>
</bean>
</beans>
इस वर्ग मैं प्रॉक्सी किया करना चाहते हैं, कोई इंटरफेस के साथ है:
यह मेरा विन्यास फाइल है , जैसे:
public class BaseService {
@Autowired
private ServiceExecutorImpl serviceExecutorImpl;
...
}
मुझे निम्न अपवाद मिलता है:
java.lang.IllegalArgumentException: Can not set mypackage.ServiceExecutorImpl field mypackage.BaseService.serviceExecutor to $Proxy26
यह वसंत उत्पादन में से कुछ पंक्तियां हैं:
13:51:12,672 [main] DEBUG [org.springframework.aop.framework.Cglib2AopProxy] - Creating CGLIB2 proxy: target source is SingletonTargetSource for target object [[email protected]]
...
13:51:12,782 [main] DEBUG [org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator] - Creating implicit proxy for bean 'serviceExecutorImpl' with 0 common interceptors and 1 specific interceptors
13:51:12,783 [main] DEBUG [org.springframework.aop.framework.JdkDynamicAopProxy] - Creating JDK dynamic proxy: target source is SingletonTargetSource for target object [[email protected]]
कोई सोचता है कि अगर यह मदद मिलेगी मैं पूर्ण उत्पादन आपूर्ति कर सकता है। मुझे नहीं पता कि वसंत मेरी कक्षा को "डबल-प्रॉक्सी" क्यों करने का प्रयास कर रहा है, और यह तब होता है जब मैं DefaultAdvisorAutoProxyCreator बीन घोषित करता हूं।
मैं अब कुछ समय से इसके साथ संघर्ष कर रहा हूं, और किसी भी मदद या विचारों की बहुत सराहना की जाएगी।
संपादित करें:
यह मेरा इंटरसेप्टर स्रोत कोड, के रूप में अनुरोध किया गया है। यह मूल रूप से विधि निष्पादन लॉग करता है (केवल @ ट्रेस के साथ एनोटेटेड विधियों को अवरुद्ध किया जाता है)। यदि विधि @Trace (false) के साथ एनोटेटेड है, तो विधि लौटने तक लॉगिंग निलंबित कर दी जाती है।
public class TraceInterceptor
implements
MethodInterceptor
{
@Override
public Object invoke(
MethodInvocation invocation)
throws Throwable
{
if(ThreadExecutionContext.getCurrentContext().isLogSuspended()) {
return invocation.proceed();
}
Method method = AopUtils.getMostSpecificMethod(invocation.getMethod(),
invocation.getThis().getClass());
Trace traceAnnotation = method.getAnnotation(Trace.class);
if(traceAnnotation != null && traceAnnotation.value() == false) {
ThreadExecutionContext.getCurrentContext().suspendLogging();
Object result = invocation.proceed();
ThreadExecutionContext.getCurrentContext().resumeLogging();
return result;
}
ThreadExecutionContext.startNestedLevel();
SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy - HH:mm:ss.SSS");
Logger.log("Timestamp: " + dateFormat.format(new Date()));
String toString = invocation.getThis().toString();
Logger.log("Class: " + toString.substring(0, toString.lastIndexOf('@')));
Logger.log("Method: " + getMethodName(method));
Logger.log("Parameters: ");
for(Object arg : invocation.getArguments()) {
Logger.log(arg);
}
long before = System.currentTimeMillis();
try {
Object result = invocation.proceed();
Logger.log("Return: ");
Logger.log(result);
return result;
} finally {
long after = System.currentTimeMillis();
Logger.log("Total execution time (ms): " + (after - before));
ThreadExecutionContext.endNestedLevel();
}
}
// Just formats a method name, with parameter and return types
private String getMethodName(
Method method)
{
StringBuffer methodName = new StringBuffer(method.getReturnType().getSimpleName() + " "
+ method.getName() + "(");
Class<?>[] parameterTypes = method.getParameterTypes();
if(parameterTypes.length == 0) {
methodName.append(")");
} else {
int index;
for(index = 0; index < (parameterTypes.length - 1); index++) {
methodName.append(parameterTypes[ index ].getSimpleName() + ", ");
}
methodName.append(parameterTypes[ index ].getSimpleName() + ")");
}
return methodName.toString();
}
}
धन्यवाद!
ठीक है, मुझे लगता है कि CGLIB प्रॉक्सी कुछ इंटरफ़ेस लागू करते हैं। लेकिन मुझे लगता है कि यह मेरे नियंत्रण से बाहर है, है ना? मूल वर्ग, जिसे मैंने लिखा है, किसी भी इंटरफेस को लागू नहीं करता है, या यहां तक कि किसी वर्ग को भी बढ़ाता है (ऑब्जेक्ट को छोड़कर)। मुझे नहीं पता कि सलाह के लिए जांच करना मेरी मदद कर सकता है, क्योंकि इस वर्ग को स्प्रिंग (@ ट्रांसेक्शनल के कारण) द्वारा सलाह दी जा रही है, और मैंने लिखा किसी भी बिंदु से नहीं। मैं यह देखने के लिए पर एक नज़र डालेगा कि यह मेरी मदद कर सकता है या नहीं। धन्यवाद! –
क्या आप इंटरसेप्टर कोड दिखा सकते हैं? – Bozho
मैंने अपने प्रश्न को इंटरसेप्टर के स्रोत के साथ संपादित किया। कोई सुराग? –