जैसा कि हम जानते हैं कि वसंत कार्यक्षमता जोड़ने के लिए परदे के पीछे का उपयोग करता है ( @Transactional
और @Scheduled
उदाहरण के लिए)। दो विकल्प हैं - जेडीके डायनेमिक प्रॉक्सी (कक्षा में गैर-रिक्त इंटरफेस को लागू करना है) का उपयोग करना, या सीजीएलआईबी कोड जनरेटर का उपयोग करके एक बाल वर्ग उत्पन्न करना। मैंने हमेशा सोचा कि प्रॉक्सीमोड मुझे JDK डायनेमिक प्रॉक्सी और CGLIB के बीच चयन करने की अनुमति देता है।
लेकिन मैं एक उदाहरण बनाने में सक्षम था जो दर्शाता है कि मेरी धारणा गलत है:
मामला एक:
सिंगलटन:
@Service
public class MyBeanA {
@Autowired
private MyBeanB myBeanB;
public void foo() {
System.out.println(myBeanB.getCounter());
}
public MyBeanB getMyBeanB() {
return myBeanB;
}
}
प्रोटोटाइप:
@Service
@Scope(value = "prototype")
public class MyBeanB {
private static final AtomicLong COUNTER = new AtomicLong(0);
private Long index;
public MyBeanB() {
index = COUNTER.getAndIncrement();
System.out.println("constructor invocation:" + index);
}
@Transactional // just to force Spring to create a proxy
public long getCounter() {
return index;
}
}
मुख्य:
MyBeanA beanA = context.getBean(MyBeanA.class);
beanA.foo();
beanA.foo();
MyBeanB myBeanB = beanA.getMyBeanB();
System.out.println("counter: " + myBeanB.getCounter() + ", class=" + myBeanB.getClass());
आउटपुट:
constructor invocation:0
0
0
counter: 0, class=class test.pack.MyBeanB$$EnhancerBySpringCGLIB$$2f3d648e
यहां हम दो चीजें देख सकते हैं:
MyBeanB
केवल एक बार त्वरित किया गया था ।- के लिए
@Transactional
कार्यक्षमता जोड़ने के लिएMyBeanB
, स्प्रिंग ने CGLIB का उपयोग किया।
केस 2:
मुझे MyBeanB
परिभाषा को सही करने दें :
@Service
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyBeanB {
इस मामले में आउटपुट है:
constructor invocation:0
0
constructor invocation:1
1
constructor invocation:2
counter: 2, class=class test.pack.MyBeanB$$EnhancerBySpringCGLIB$$b06d71f2
यहां हम दो चीजें देख सकते हैं:
MyBeanB
3 बार त्वरित किया गया था ।- के लिए
@Transactional
कार्यक्षमता जोड़ने के लिएMyBeanB
, स्प्रिंग ने CGLIB का उपयोग किया।
क्या आप बता सकते हैं कि क्या चल रहा है? प्रॉक्सी मोड वास्तव में कैसे काम करता है?
पुनश्च
मैंने प्रलेखन पढ़ा है:
/**
* Specifies whether a component should be configured as a scoped proxy
* and if so, whether the proxy should be interface-based or subclass-based.
* <p>Defaults to {@link ScopedProxyMode#DEFAULT}, which typically indicates
* that no scoped proxy should be created unless a different default
* has been configured at the component-scan instruction level.
* <p>Analogous to {@code <aop:scoped-proxy/>} support in Spring XML.
* @see ScopedProxyMode
*/
लेकिन यह मेरे लिए स्पष्ट नहीं है।
अपडेट करें
केस 3:
मैंने एक और मामले की जांच की, जिसमें मैंने इंटरफ़ेस निकाला MyBeanB
:
public interface MyBeanBInterface {
long getCounter();
}
@Service
public class MyBeanA {
@Autowired
private MyBeanBInterface myBeanB;
@Service
@Scope(value = "prototype", proxyMode = ScopedProxyMode.INTERFACES)
public class MyBeanB implements MyBeanBInterface {
और इस मामले में आउटपुट है:
constructor invocation:0
0
constructor invocation:1
1
constructor invocation:2
counter: 2, class=class com.sun.proxy.$Proxy92
यहां हम दो चीजें देख सकते हैं:
MyBeanB
3 बार त्वरित किया गया था ।- के लिए
@Transactional
कार्यक्षमता जोड़ने के लिएMyBeanB
, स्प्रिंग ने JDK डायनेमिक प्रॉक्सी का उपयोग किया।
MyBeanB
कक्षा किसी भी इंटरफेस का विस्तार नहीं करती है, इसलिए यह आश्चर्यजनक नहीं है कि आपका कंसोल CGLIB प्रॉक्सी उदाहरण दिखाता है। 3 मामले में आप एक इंटरफ़ेस लागू करते हैं और लागू करते हैं, फलस्वरूप आपको JDK प्रॉक्सी मिलता है। आप अपने परिचयात्मक पाठ में भी इसका वर्णन करते हैं।
<aop:config proxy-target-class="true">
या के माध्यम से कॉन्फ़िगर किया @EnableAspectJAutoProxy(proxyTargetClass = true)
गया है।