2011-01-23 9 views
9

मैं वसंत 3 का उपयोग करके अर्द्ध-बड़े एप्लिकेशन पर काम कर रहा हूं और सैकड़ों उपयोगकर्ताओं को एक बार में फेंकते समय प्रदर्शन समस्याओं में भाग ले रहा हूं। मैं वसंत की एओपी प्रॉक्सी का उपयोग करके कई अनुरोध स्कोप्ड बीन्स का उपयोग कर रहा हूं और मैं देख सकता हूं कि हर बार जब मैं इन बीन्स में से किसी एक पर किसी भी विधि को कॉल करता हूं, तो CGLIB इंटरसेप्टर को बुलाया जाता है, जिसे तब सारबीन फैक्ट्री.getबीन() कहते हैं, जो ऐड() को कॉल करता है मौजूदा वसंत सेम का एक सिंक्रनाइज़ सेट। चूंकि यह ऐड() सिंक्रनाइज़ किया गया है, इसलिए यह प्रभावी रूप से सर्वर को लॉक करता है जब हजारों कॉल सभी एक ही सूची में जोड़ने का इंतजार कर रहे हैं।बहुत से एओपी अनुरोध का उपयोग करते समय प्रदर्शन समस्याएं स्कैन बीन्स

क्या अनुरोधित स्कैन बीन्स का उपयोग करके इसे पाने का कोई तरीका है? मैंने स्प्रिंग प्रलेखन में पढ़ा है कि अगर बीन किसी भी इंटरफेस को लागू करता है तो CGLIB का उपयोग नहीं किया जाता है (http://static.springsource.org/spring/docs/2.0.0/reference/aop.html#d0e9015) लेकिन मेरा अनुरोध स्कैन बीन्स सभी एक लागू (वास्तव में वही) और यह अभी भी हो रहा है। और मुझे निश्चित रूप से अनुरोध करने के लिए सेम की आवश्यकता है क्योंकि उनके कुछ फ़ील्ड एक विशेष अनुरोध के लिए ऐप के एक हिस्से में गणना की जाती हैं और फिर मैं उसी अनुरोध के दौरान ऐप के एक अलग हिस्से में अपना मूल्य प्राप्त करने के लिए स्पेल का उपयोग करता हूं। मुझे लगता है कि अगर मैंने बीन्स प्रोटोटाइप स्कॉप्ड किया है, तो जब मैं दूसरी बार उन्हें प्राप्त करने के लिए स्पेल का उपयोग करता हूं तो मेरे पास एक ताजा वस्तु होगी।

यहां एक कोड नमूना है जो मेरी समस्या का वर्णन करता है। टिप्पणियों के लिए आखिरी दो पंक्तियां देखें, जिसमें वर्णन किया गया है कि वास्तव में मुझे समस्याएं कहां हैं।

  • मैं एक स्प्रिंग बीन अनुरोध हर विधि सेम पर किए गए कॉल को प्रॉक्सी के बिना scoped कर सकते हैं:

    <!-- Spring config --> 
    <bean name="someBean" class="some.custom.class.SomeClass" scope="request"> 
        <property name="property1" value="value1"/> 
        <property name="property2" value="value2"/> 
        <aop:scoped-proxy/> 
    </bean> 
    
    <bean name="executingClass" class="some.other.custom.class.ExecutingClass" scope="singleton"> 
        <property name="myBean" ref="someBean" /> 
    </bean> 
    
    
    public Interface SomeInterface { 
        public String getProperty1(); 
        public void setProperty1(String property); 
        public String getProperty2(); 
        public void setProperty2(String property); 
    } 
    
    public class SomeClass implements SomeInterface { 
        private String property1; 
        private String property2; 
    
        public String getProperty1() { return propery1; } 
        public void setProperty1(String property) { property1=property;} 
    
        public String getProperty2() { return propery2; } 
        public void setProperty2(String property) { property2=property;} 
    } 
    
    
    public class ExecutingClass { 
        private SomeInterface myBean; 
    
        public void execute() { 
         String property = myBean.getProperty1(); // CGLIB interceptor is invoked here, registering myBean as a bean 
         String otherProperty = myBean.getProperty2(); // CGLIB interceptor is invoked here too! Seems like this is unnecessary. And it's killing my app. 
        } 
    } 
    

    मेरे विचारों निम्न में से एक रहे हैं? और हर विधि को "अंतिम" के रूप में चिह्नित किए बिना?

या ...

  • मैं वसंत के सेम कारखाने एक बीन कैश है कि यदि एक सेम AbstractBeanFactory.getBean कॉल करने से पहले कैश किया गया है की जाँच करेगा लागू करने के लिए ओवरराइड कर सकते हैं()? और यदि हां, तो मैं अपने कस्टम बीन कारखाने का उपयोग करने के लिए वसंत को कहां कॉन्फ़िगर करूँ?
+0

1 कॉल ठीक है, लेकिन 2 एक्स कॉल आपके ऐप को मार देते हैं? –

+0

अगर इसे पहली बार बीन संदर्भित किया गया था, तो यह ठीक रहेगा। यदि यह प्रॉक्सी क्लास को हर बार कॉल करता है तो मैं बीन पर किसी भी विधि को कॉल करता हूं, जो मेरा ऐप मारता है। – Cameron

उत्तर

4

जैसा कि यह पता चला है, स्प्रिंग वास्तव में अनुरोध गुणों में अनुरोध स्कैन बीन्स को कैश करता है। इसलिए जब AbstractBeanFactory.getBean() aop प्रॉक्सी की वजह से हर सेम विधि कॉल पर बुलाया हो जाता है, यह केवल का कारण बनता है जोड़ने के लिए वसंत

public Object get(String name, ObjectFactory objectFactory) { 
    RequestAttributes attributes = RequestContextHolder.currentRequestAttributes(); 
    Object scopedObject = attributes.getAttribute(name, getScope()); 
    if (scopedObject == null) { 
     scopedObject = objectFactory.getObject(); 
     attributes.setAttribute(name, scopedObject, getScope()); 
    } 
    return scopedObject; 
} 

: यदि आप उत्सुक हैं, तो AbstractRequestAttributesScope, जो RequestScope फैली पर एक नज़र उस सिंक्रनाइज़ किए गए सेट पर यदि बीन अनुरोध गुणों में पहले से नहीं मिला था।

मेरे अनुरोध पर हर विधि कॉल के प्रॉक्सीइंग से बचने के लिए स्कैन किए गए सेम अभी भी जटिलता को कम करेंगे लेकिन इस कैशिंग के साथ, प्रदर्शन प्रभाव कम होगा। मुझे लगता है कि धीमी प्रदर्शन कुछ ऐसा है जो मुझे रहने के लिए जा रहा है अगर मैं अनुरोधित टन बीन्स चाहता हूं और अभी भी एक समय में अनुरोधों की एक टन की सेवा करता हूं।

2

दिलचस्प सवाल।

यह पता चला है कि वसंत की स्कॉप्ड प्रॉक्सी हल की गई वस्तुओं को कैश नहीं करती है, ताकि स्कॉप्ड प्रॉक्सी की हर पहुंच को getBean() कहा जा सके। प्रॉक्सी तंत्र के बारे में

public class MyScopedProxy implements SomeInterface, BeanFactoryAware { 

    private BeanFactory factory; 
    private Scope scope; 
    private String targetBeanName; 
    private ThreadLocal<SomeInterface> cache = new ThreadLocal<SomeInterface>(); 

    private SomeInterface resolve() { 
     SomeInterface v = cache.get(); 
     if (v == null) { 
      v = (SomeInterface) factory.getBean(targetBeanName); 
      cache.set(v); 
      scope.registerDestructionCallback(targetBeanName, new Runnable() { 
       public void run() { 
        cache.remove(); 
       } 
      }); 
     } 
     return v; 
    } 

    public void setBeanFactory(BeanFactory factory) { 
     this.factory = factory; 
     this.scope = ((ConfigurableBeanFactory) factory).getRegisteredScope("request"); 
    } 

    public String getProperty() { 
     return resolve().getProperty(); 
    } 

    ... 
} 

:

समाधान के लिए, यदि आप एक गरीब आदमी का कैशिंग scoped प्रॉक्सी, कुछ इस तरह बना सकते हैं (अपरीक्षित, लक्ष्य सेम अनुरोध-दायरे होना चाहिए, लेकिन बिना <aop:scoped-proxy />) के विपरीत अन्य एओपी प्रॉक्सी, स्कॉप्ड प्रॉक्सी डिफ़ॉल्ट रूप से CGLIB हैं, आप इसे <aop:scoped-proxy proxy-target-class = "false" /> सेट करके ओवरराइड कर सकते हैं, लेकिन इससे इस मामले में सहायता नहीं होगी।

+0

यदि मुझे एक से अधिक इंटरफ़ेस के साथ एक से अधिक स्थानों में यह समस्या है, तो मुझे प्रत्येक इंटरफ़ेस के लिए एक नई प्रॉक्सी बनाना होगा? क्या AbabBeanFactory.getBean() को ओवरराइड करना और वहां एक बीन कैश लागू करना संभव होगा? यदि ऐसा है, तो मैं यह नहीं समझ सकता कि स्प्रिंग कॉन्फ़िगरेशन में मेरे कस्टम बीन फैक्ट्री को निर्दिष्ट करने के लिए कहां है। – Cameron

+0

मेरा जवाब देखें; अनुरोध गुणों में अनुरोध स्कोप द्वारा अनुरोधित स्कॉप्ड बीन्स को कैश किया जाता है। किसे पता था! – Cameron

0

एक विकल्प के साथ एक scoped प्रॉक्सी इंजेक्शन लगाने को बदलने के लिए है एक lookup-method:

public abstract class ExecutingClass { 
    protected abstract SomeInterface makeMyBean(); 

    public void execute() { 
     SomeInterface myBean = makeMyBean(); 
     String property = myBean.getProperty1(); 
     String otherProperty = myBean.getProperty2(); 
    } 
} 

कि वसंत सुनिश्चित करेगा सेम के लिए कहा जाता है केवल एक बार अनुरोध के अनुसार, किसी भी भूमि के ऊपर scoped प्रॉक्सी के कारण को खत्म करने, और ढेर छोटा निशान। यह कम लचीला है (इसमें आप स्वेप्ड बीन के अनुरोध के लिए मनमाने ढंग से संदर्भ साझा नहीं कर सकते हैं और स्कॉप्ड प्रॉक्सी सही बीन का उपयोग कर सकते हैं) लेकिन आपको लचीलापन की आवश्यकता नहीं हो सकती है।

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