2011-12-07 22 views
7

मैं उदाहरण के बजाय बीनमेनगर का उपयोग कर सीडीआई प्रबंधित बीन्स के उदाहरण बनाने की कोशिश कर रहा हूं। चयन()।() प्राप्त करें।BeanManager के माध्यम से सीडीआई (वेल्ड) प्रबंधित बीन्स कैसे बनाएं और नष्ट करें?

यह किसी समस्या के लिए एक समाधान के रूप में सुझाया गया था जिसे मैं एप्लीकेशनस्कोप्ड बीन्स और उनके आश्रितों के कचरा संग्रह के साथ कर रहा हूं - पृष्ठभूमि के लिए CDI Application and Dependent scopes can conspire to impact garbage collection? देखें और यह सुझाया गया कार्यवाही।

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

मेरे वर्तमान दृष्टिकोण एक BeanManagerUtil वर्ग के भीतर सेम बनाने के लिए, और वापसी बीन, उदाहरण के लिए, और CreationalContext का एक समग्र वस्तु है:

public class BeanManagerUtil { 

    @Inject private BeanManager beanManager; 

    @SuppressWarnings("unchecked") 
    public <T> DestructibleBeanInstance<T> getDestructibleBeanInstance(final Class<T> type, 
      final Annotation... qualifiers) { 

     DestructibleBeanInstance<T> result = null; 
     Bean<T> bean = (Bean<T>) beanManager.resolve(beanManager.getBeans(type, qualifiers)); 
     if (bean != null) { 
      CreationalContext<T> creationalContext = beanManager.createCreationalContext(bean); 
      if (creationalContext != null) { 
       T instance = bean.create(creationalContext); 
       result = new DestructibleBeanInstance<T>(instance, bean, creationalContext); 
      } 
     } 
     return result; 
    } 
} 

public class DestructibleBeanInstance<T> { 

    private T instance; 
    private Bean<T> bean; 
    private CreationalContext<T> context; 

    public DestructibleBeanInstance(T instance, Bean<T> bean, CreationalContext<T> context) { 
     this.instance = instance; 
     this.bean = bean; 
     this.context = context; 
    } 

    public T getInstance() { 
     return instance; 
    }  

    public void destroy() { 
     bean.destroy(instance, context); 
    } 
} 

इस से, बुला कोड में, मैं तो प्राप्त कर सकते हैं वास्तविक उदाहरण के लिए, बाद में पुनः प्राप्ति के लिए एक नक्शा में रख, और सामान्य रूप में उपयोग:

private Map<Worker, DestructibleBeanInstance<Worker>> beansByTheirWorkers = 
    new HashMap<Worker, DestructibleBeanInstance<Worker>>(); 
... 
DestructibleBeanInstance<Worker> destructible = 
     beanUtils.getDestructibleBeanInstance(Worker.class, workerBindingQualifier); 
Worker worker = destructible.getInstance(); 
... 

जब मैंने इसे पूरा कर लेने, मैं ध्वंसशील आवरण देखने और फोन को नष्ट() उस पर कर सकते हैं और सेम और इसके आश्रितों को साफ किया जाना चाहिए:

DestructibleBeanInstance<JamWorker> workerBean = 
     beansByTheirWorkers.remove(worker); 
workerBean.destroy(); 
worker = null; 

हालांकि, कई कार्यकर्ताओं चल रहा है और 20 मिनट या तो के लिए मेरे JBoss (7.1.0.Alpha1-स्नैपशॉट) छोड़ने के बाद, मैं अभी भी जीसी

2011.002: [GC 
Desired survivor size 15794176 bytes, new threshold 1 (max 15) 
1884205K->1568621K(3128704K), 0.0091281 secs] 

होने वाली अभी तक एक jmap हिस्टोग्राम शो देख सकते हैं पुराने मजदूरों और उनके आश्रित उदाहरणों के आसपास लटका, unGCed। मैं क्या खो रहा हूँ?

डीबगिंग के माध्यम से, मैं देख सकता हूं कि बनाए गए बीन के संदर्भ क्षेत्र में सही वर्कर प्रकार, कोई अधूरा इंस्टेंस नहीं है और कोई अभिभावक निर्भर नहीं है। इसमें कई आश्रित संस्थान हैं, जो कार्यकर्ताओं के खेतों से अपेक्षित हैं।

वर्कर पर इन क्षेत्रों में से एक वास्तव में एक उदाहरण है, और जब मैं प्रोग्रामेटिक इंस्टेंस लुकअप के माध्यम से पुनर्प्राप्त एक वर्कर के साथ इस क्षेत्र की तुलना करता हूं, तो उनके पास थोड़ा अलग CreationalContext मेकअप होता है। श्रमिक पर इंस्टेंस फ़ील्ड इंस्टेंस के माध्यम से देखा गया है, कार्यकर्ता स्वयं अधूरा निवेश के तहत है, जबकि बीनमेनगर से प्राप्त श्रमिक पर इंस्टेंस फ़ील्ड नहीं है। दोनों के पास समान माता-पिता निर्भरता और निर्भर उद्यम हैं।

यह मुझे बताता है कि मैंने सही तरीके से पुनर्प्राप्ति को प्रतिबिंबित नहीं किया है। क्या यह विनाश की कमी में योगदान दे सकता है?

आखिरकार, जब डीबगिंग हो, तो मैं अपने DestructibleBeanInstance.destroy() में bean.destroy() को बुलाया जा सकता हूं, और यह ManagedBean.destroy के माध्यम से जाता है, और मैं निर्भर करता हूं कि निर्भर वस्तुओं को नष्ट कर दिया जा रहा है। कृपया()। हालांकि वे अभी भी कचरा इकट्ठा नहीं मिलता है!

इस पर किसी भी मदद की बहुत सराहना की जाएगी! धन्यवाद।

उत्तर

2

मैं आपके द्वारा चिपकाए गए कोड में कुछ चीजें बदल दूंगा।

  1. उस कक्षा को नियमित जावा श्रेणी, कोई इंजेक्शन और बीनमेनगर में पास करें। उस तरह से कुछ गड़बड़ हो सकता है। यह संभवतः, लेकिन संभवतः नहीं है।
  2. BeanManager.createCreationContext(null) का उपयोग कर एक नया क्रिएशन कॉन्टेक्स्ट बनाएं जो आपको अनिवार्य रूप से एक निर्भर दायरा देगा जिसे आप CreationalContext.release() पर कॉल करके कर सकते हैं।

आप आप पहले से ही DestructibleBeanInstance में है CreationalContext को रिलीज विधि को फोन करके सही ढंग से जिस तरह से आप चाहते हैं काम करने के लिए सब कुछ प्राप्त करने में सक्षम हो सकता है, यह है कि CreationalContext में कोई अन्य Beans यह सोचते हैं कि गंदगी आपके आवेदन करेंगे। पहले कोशिश करें और देखें कि क्या यह चीजों को गड़बड़ कर देता है।

+0

धन्यवाद, जेसन। मैंने आपके द्वारा सुझाए गए परिवर्तन किए हैं, लेकिन फिर भी कोई कचरा संग्रह नहीं देख रहा था। हालांकि जब मैंने _full_ जीसी के लिए इंतजार किया, तो दोनों दृष्टिकोणों ने वस्तुओं को एकत्रित किया - सफलता! यह पहले एक पूर्ण जीसी पर मामला नहीं था। यदि आपके पास समय है, तो कृपया आप '.createCreationContext (null)' और '.createCreationContext (bean) 'के बीच के अंतर को समझा सकते हैं? मैंने पूर्व में एक एक्सटेंशन लिखने के लिए दस्तावेज़ों में देखा है, लेकिन मैंने सोचा था कि उस समय के 'बीन' संस्करण के लिए था (यदि आप देखते हैं कि मेरा क्या मतलब है) पहले से मौजूद नहीं था? मदद के लिए एक बार फिर से धन्यवाद। –

+0

spec के अनुसार यह आपको बीन का एक गैर-प्रासंगिक उदाहरण देता है, इसलिए इसे बनाने के लिए चलाए गए कोड के उस भाग के अलावा इसके अलावा इसका कोई अन्य संदर्भ नहीं होना चाहिए। मैंने कुछ अतिरिक्त अंतर्दृष्टि के लिए पीट मुइर से पूछा, लेकिन मैंने अभी तक नहीं सुना है। – LightGuard

2

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

1

बीन विनाश को संभालने के लिए एक गतिशील प्रॉक्सी का उपयोग करने के लिए आपकी समस्या का समाधान करने का एक अच्छा तरीका हो सकता है। एक बीन क्लास इंस्टेंस प्रोग्रामैटिकल प्राप्त करने के लिए कोड होगा:

public static <B> B getBeanClassInstance(BeanManager beanManager, Class<B> beanType, Annotation... qualifiers) { 
    final B result; 
    Set<Bean<?>> beans = beanManager.getBeans(beanType, qualifiers); 
    if (beans.isEmpty()) 
     result = null; 
    else { 
     final Bean<B> bean = (Bean<B>) beanManager.resolve(beans); 
     if (bean == null) 
      result = null; 
     else { 
      final CreationalContext<B> cc = beanManager.createCreationalContext(bean); 
      final B reference = (B) beanManager.getReference(bean, beanType, cc); 
      Class<? extends Annotation> scope = bean.getScope(); 
      if (scope.equals(Dependent.class)) { 
       if (beanType.isInterface()) { 
        result = (B) Proxy.newProxyInstance(bean.getBeanClass().getClassLoader(), new Class<?>[] { beanType, 
          Finalizable.class }, new InvocationHandler() { 
         @Override 
         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
          if (method.getName().equals("finalize")) { 
           bean.destroy(reference, cc); 
          } 
          try { 
           return method.invoke(reference, args); 
          } catch (InvocationTargetException e) { 
           throw e.getCause(); 
          } 
         } 
        }); 
       } else 
        throw new IllegalArgumentException("If the resolved bean is dependent scoped then the received beanType should be an interface in order to manage the destruction of the created dependent bean class instance."); 
      } else 
       result = reference; 
     } 
    } 
    return result; 
} 

interface Finalizable { 
    void finalize() throws Throwable; 
} 

इस तरह उपयोगकर्ता कोड सरल है। इसे विनाश का ख्याल रखना नहीं है। इस एप्रोच की सीमा यह है कि जब प्राप्त बीन टाइप एक इंटरफेस नहीं है और हल किया गया बीन वर्ग @Dependent समर्थित नहीं है। लेकिन चारों ओर काम करना आसान है। बस एक इंटरफेस का उपयोग करें। मैंने इस कोड का परीक्षण किया (जेबॉस 7.1.1 के साथ) और यह निर्भर राज्य सत्र सत्र बीन्स के लिए भी काम करता है।

+0

उत्कृष्ट विचार, धन्यवाद @ रेडरन –