2013-03-16 4 views
5

मैं जावा ईई/जेएसएफ में नया हूं और अब सीडीआई क्वालिफायर के बारे में पढ़ता हूं - कक्षा कार्यान्वयन को बदलने की संभावना। यह बहुत अच्छा है लेकिन मुझे एक सवाल है। जहां तक ​​मैं समझता हूं कि मैं क्वालीफायर का उपयोग करके कक्षा कार्यान्वयन को बदल सकता हूं लेकिन मुझे इसे हर जगह बदलने की जरूरत है, मैं इस कार्यान्वयन का उपयोग करता हूं। एक स्थान पर ऐसा करने का सबसे अच्छा समाधान क्या है? जावा ईई के बारे में अपने छोटे ज्ञान के साथ मैंने यह पता लगाया।एकाधिक कक्षा कार्यान्वयन के साथ सीडीआई क्वालीफायर का उपयोग कैसे करें?

आइए कल्पना करें कि हम सरल कैलकुलेटर एप्लिकेशन बना रहे हैं।

  1. Calculator
  2. MockCalculator (इकाई परीक्षण के लिए) (कैलकुलेटर के बुनियादी कार्यान्वयन)
  3. ScientificCalculator (कैलकुलेटर के वैज्ञानिक कार्यान्वयन)
  4. MiniCalculator (कम से कम संभावनाओं के साथ)
  5. : हम कुछ वर्गों बनाने की जरूरत
  6. क्वालीफायर @Calculator (कैलकुलेटर के वास्तविक कार्यान्वयन को इंगित करेगा; क्या मुझे प्रत्येक कार्यान्वयन के लिए क्वालीफायर बनाना चाहिए?)

यहां सवाल है। मुझे कैलकुलेटर के चार कार्यान्वयन मिल गए हैं और मैं उनमें से एक को कुछ स्थानों पर उपयोग करना चाहता हूं लेकिन केवल एक समय में (प्रारंभिक परियोजना चरण में मैं MiniCalculator का उपयोग करूंगा, फिर Calculator और इसी तरह)। वस्तु को इंजेक्शन दिए जाने पर हर जगह परिवर्तन कोड के बिना कार्यान्वयन कैसे बदल सकता हूं? क्या मुझे कारखाना बनाना चाहिए जो इंजेक्शन के लिए ज़िम्मेदार होगा और method injector के रूप में काम करेगा? क्या मेरा समाधान सही और सार्थक है?

फैक्टरी

@ApplicationScoped 
public class CalculatorFctory implements Serializable { 
    private Calculator calc; 

    @Produces @Calculator Calculator getCalculator() { 
     return new Calculator(); 
    } 
} 

कक्षा जो कैलक्यूलेटर

public class CalculateUserAge { 
    @Calculator 
    @Inject 
    private Calculator calc; 
} 

का उपयोग करता है यह सही समाधान है? अगर मैं गलत हूं या कोई बेहतर समाधान है तो कृपया मुझे सही करें। धन्यवाद!।

उत्तर

9

यदि आप फ़ैक्टरी विधि का उपयोग करके अपने कोड में कार्यान्वयन को स्वैप करना चाहते हैं तो आपकी फैक्ट्री विधि बीन्स का प्रबंधन कर रही है, न कि सीडीआई और इसलिए @Calculator की वास्तव में कोई आवश्यकता नहीं है।

@ApplicationScoped 
    public class CalculatorFactory implements Serializable { 
    enum CalculatorType{MiniCaculator,ScientificCaculator,MockCalculator}; 
    Calculator getCalculator(CalculatorType calctype) { 
       switch(calctype) 
        case MiniCaculator : return new MiniCalculator(); 
        case ScientificCalculator : new ScientificCalculator(); 
        case MockCalculator : new MockCalculator(); 
        default:return null; 
      } 
     } 
public class CalculatorScientificImpl {  
    private Calculator calc = 
      CalculatorFactory.getCaclulator(CaclutorType.ScientificCalculator); 
    doStuff(){} 
} 

public class CalculatorTest {  
    private Calculator calc = 
       CalculatorFactory.getCaclulator(CaclutorType.MockCalculator); 
    doStuff(){} 
} 

हालांकि आप अपने Caclulator सेम CDI इंजेक्शन और जीवन चक्र प्रबंधन @PostConstruct आदि का उपयोग तो आप नीचे दिए तरीकों में से एक का उपयोग कर सकते के लिए प्रबंधित होना चाहते हैं।

दृष्टिकोण 1:

लाभ: आप @Named ("miniCaclulator") का उपयोग

नुकसान एनोटेशन बनाने से बचना कर सकते हैं: संकलक इस दृष्टिकोण अगर साथ एक त्रुटि नहीं देंगे वहाँ मिनीकैक्लुलेटर से xyzCaclulator कहने का नाम बदल गया है।

@Named("miniCaclulator") 
class MiniCalculator implements Calculator{ ... } 

@ApplicationScoped 
public class CalculatorFactory implements Serializable { 
    private calc; 

    @Inject 
    void setCalculator(@Named("miniCaclulator") Caclulator calc) { 
     this.calc = calc; 
    } 
} 

दृष्टिकोण 2:आप एक कारखाने विधि का उपयोग कर रहे हैं, तो आपके वस्तु उत्पन्न करने के लिए: अनुशंसित

@Qualifier 
@Retention(RUNTIME) 
@Target({FIELD, TYPE, METHOD}) 
public @interface MiniCalculator{ 
} 

@ApplicationScoped 
public class CalculatorFctory implements Serializable { 
    private calc; 

    @Inject 
    void setCalculator(@MiniCalculator calc) { 
     this.calc = calc; 
    } 
} 

दृष्टिकोण 3 (संकलक इंजेक्शन का ट्रैक यदि कोई इंजेक्शन विफल रहता है रखता है) .ट्स लाइफसाइकिल को सीडीआई नहीं किया जाएगा लेकिन इंजेक्शन @ इंजेक्ट का उपयोग करके ठीक काम करेगा।

@ApplicationScoped 
public class CalculatorFactory implements Serializable { 
    private Calculator calc;  
    @Produces Calculator getCalculator() { 
     return new Calculator(); 
    } 
}  
public class CalculateUserAge { 
    @Inject 
    private Calculator calc; 
} 

तीनों दृष्टिकोण के परीक्षण के लिए काम करेंगे, कहते हैं कि तुम एक वर्ग CaculatorTest नामित है,

class ScientificCalculatorTest{   
    Caclulator scientificCalculator;   
    @Inject 
    private void setScientificCalculator(@ScientificCalculator calc) { 
       this.scientificCalculator = calc; 
      }   
    @Test 
    public void testScientificAddition(int a,int b){ 
     scientificCalculator.add(a,b); 
     .... 
    } 
    } 

आप अपने परीक्षण में एक नकली कार्यान्वयन उपयोग करने के लिए तो कुछ इस तरह करना चाहते हैं,

class CalculatorTest{   
     Caclulator calc;   
     @PostConstruct 
       init() { 
        this.calc = createMockCaclulator(); 
       } 
     @Test 
     public void testAddition(int a,int b){ 
      calc.add(a,b); 
      ..... 
     } 
     } 
+0

कृपया अपनी टिप्पणी के अनुसार मेरा अपडेट देखें। इसके अलावा, निर्माता और वे जो भी लौटाते हैं उन्हें सीडीआई द्वारा प्रबंधित किया जाता है ... – rdcrng

+1

यदि आप इसे स्वयं कॉल करने जा रहे हैं तो '@ प्रोड्यूस' के साथ कुछ भी टिप्पणी करने का कोई कारण नहीं है। – rdcrng

+0

आप इस सेवा को सीडीआई बीन में कैसे इंजेक्ट करेंगे? हम '@Produces @myservice @WebServiceRef (lookup =" जावा: ऐप/सेवा/भुगतान सेवा ") {} @ इंजेक्ट @ myservice MyWebService का उपयोग करेंगे; 'इस मामले में कंटेनर MyWebServiceImpl जीवन चक्र का प्रबंधन नहीं करता है, यह केवल इसे –

9

यहां कई मुद्दे हैं।

  1. पूरे एप्लिकेशन में वांछित कार्यान्वयन को बदलने का सबसे अच्छा तरीका क्या है? @Alternatives में देखें।
  2. क्या मुझे प्रत्येक कार्यान्वयन के लिए योग्यता की आवश्यकता है? नहीं, this एक लंबा और विस्तृत स्पष्टीकरण के लिए उत्तर देखें।
  3. क्या मुझे यह निर्धारित करने के लिए निर्माता का उपयोग करना चाहिए कि कौन सा कार्यान्वयन इंजेक्शन दिया गया है? वह समाधान हो सकता है जो आप चाहते हैं, लेकिन मुझे शक है। निर्माता आमतौर पर कुछ प्रकार के प्रारंभिक प्रदर्शन करने के लिए उपयोग किए जाते हैं जिन्हें कन्स्ट्रक्टर/@PostConstruct में नहीं किया जा सकता है। इंजेक्शन प्वाइंट का निरीक्षण करने और इंजेक्ट करने के बारे में रनटाइम निर्णय लेने के लिए आप इसका इस्तेमाल भी कर सकते हैं। कुछ सुराग के लिए लिंक 2 देखें।
  4. क्या यह समाधान सही है? यह काम करेगा, लेकिन कार्यान्वयन को बदलने के लिए आपको अभी भी कोड के साथ गड़बड़ करनी होगी, इसलिए पहले 1. पर विचार करें। @Calculator Calculator भी अत्यधिक अनावश्यक लगता है। दोबारा, लिंक 2 देखें।

    @ApplicationScoped 
    public class CalculatorFctory implements Serializable { 
        private Calculator calc; 
    
        @Produces @Calculator Calculator getCalculator() { 
         return new Calculator(); 
        } 
    } 
    

अद्यतन:

CDI क्वालिफायर निर्भरता समाधान के लिए इसके अलावा प्रकार करने के लिए उपयोग करता है। दूसरे शब्दों में, जब तक केवल एक ही प्रकार होता है जो इंजेक्शन बिंदु के प्रकार से मेल खाता है, अकेले प्रकार पर्याप्त हैं और क्वालिफायर की आवश्यकता नहीं है। क्वालिफायर असंबद्धता के लिए हैं जब अकेले प्रकार पर्याप्त नहीं हैं।

उदाहरण के लिए:

@Inject ImplOne bean; 

या

@Inject ImplTwo bean; 

है यही कारण है कि मैं कहता हूँ @Calculator Calculator:

public class ImplOne implements MyInterface { 
    ... 
} 

public class ImplTwo implements MyInterface { 
    ... 
} 

या तो कार्यान्वयन इंजेक्षन करने में सक्षम होने के लिए, यदि आप किसी भी क्वालिफायर की जरूरत नहीं है अनावश्यक है यदि आप प्रत्येक कार्यान्वयन के लिए क्वालीफायर परिभाषित करते हैं, तो आप अधिक लाभ नहीं उठा रहे हैं, साथ ही साथ इस प्रकार का उपयोग भी कर सकते हैं। कहो, दो क्वालिफायर @QualOne और @QualTwo:

@Inject @QualOne ImplOne bean; 

और

@Inject @QualTwo ImplTwo bean; 

उदाहरण सीधे ऊपर पिछले उदाहरण कोई असंतुष्ट अस्पष्टता पहले से ही अस्तित्व में है के बाद से कुछ भी हासिल नहीं होता है।

@Inject @QualOne MyInterface bean; // to inject TypeOne 

और

@Inject @QualTwo MyInterface bean; // to inject TypeTwo 

@Produces हालांकि ओ पी का उपयोग नहीं किया जाना चाहिए: जहां विशेष रूप से कार्यान्वयन प्रकार के लिए पहुँच नहीं है

ज़रूर, तुम मामलों के लिए ऐसा कर सकते हैं जब वह कैलिफोर्निया कार्यान्वयन सीडीआई प्रबंधित करने के लिए चाहता है।

@Avinash सिंह - CDI, कुछ भी वे लौट के रूप में रूप में अच्छी तरह @Produces का प्रबंधन करता है जब तक कि यह CDI कि प्रणाली को बुलाती है। यदि आप कृपया this section of the spec देखें। यह लौटने `शामिल @ ... scoped सेम जो निर्भरता इंजेक्शन, जीवन-चक्र कॉलबैक का समर्थन करेंगे, आदि

मैं यहाँ कुछ विवरण अनदेखी की है, तो विचार करना दो निम्नलिखित:

public class SomeProducer { 

    @Inject ImplOne implOne; 
    @Inject ImplTwo implTwo; 
    @Inject ImplThree implThree; 

    @Produces 
    public MyInterface get() { 
     if (conditionOne()) { 
      return implOne; 
     } else if (conditionTwo()) { 
      return implTwo; 
     } else { 
      return implThree; 
     } 
    } 
} 

और

public class SomeProducer { 

    @Produces 
    public MyInterface get() { 
     if (conditionOne()) { 
      return new ImplOne(); 
     } else if (conditionTwo()) { 
      return new ImplTwo(); 
     } else { 
      return new ImplThree; 
     } 
    } 
} 

फिर, पहले उदाहरण में, सीडीआई उत्पादक से वापस आने वाले जीवन चक्र (यानी @PostConstruct और @Inject समर्थन) का प्रबंधन करेगा, लेकिन दूसरे में यह नहीं होगा।

मूल प्रश्न पर वापस जाएं - स्रोत को संशोधित किए बिना कार्यान्वयन के बीच स्विच करने का सबसे अच्छा तरीका क्या है? धारणा यह है कि आप परिवर्तन को व्यापक रूप से आवेदन करना चाहते हैं।

@Default 
public class ImplOne implements MyInterface { 
    ... 
} 

@Alternative 
public class ImplTwo implements MyInterface { 
    ... 
} 

@Alternative 
public class ImplThree implements MyInterface { 
    ... 
} 

फिर, किसी भी @Inject MyInterface instance के लिए किसी भी, ImplOne इंजेक्ट किया जाएगा, जब तक

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"> 
    <alternatives> 
     <class>ImplTwo</class> 
    </alternatives> 
</beans> 

निर्दिष्ट किया जाता है, जिसमें मामले ImplTwo हर जगह इंजेक्शन दिया जाएगा।

इसके अलावा अद्यतन

वहाँ वास्तव में इस तरह के EJBs और वेब सेवाओं के रूप में जावा ईई वातावरण में चीजें हैं जो CDI द्वारा प्रबंधित नहीं कर रहे हैं, कर रहे हैं।

आप एक सीडीआई प्रबंधित बीन में एक वेब सेवा कैसे इंजेक्ट करेंगे? यह वास्तव में आसान है:

@WebServiceRef(lookup="java:app/service/PaymentService") 
PaymentService paymentService; 

यही है, वहां आपके पास भुगतान सेवा का वैध संदर्भ होगा जो सीडीआई के बाहर प्रबंधित किया जाता है।

लेकिन, यदि आप हर जगह पूर्ण @WebServiceRef(lookup="java:app/service/PaymentService") का उपयोग नहीं करना चाहते हैं तो आपको इसकी आवश्यकता है? क्या होगा यदि आप केवल इसे टाइप करके इंजेक्ट करना चाहते हैं? तो फिर तुम इस कहीं कार्य करें:

@Produces @WebServiceRef(lookup="java:app/service/PaymentService") 
PaymentService paymentService; 

और किसी भी CDI सेम है कि भुगतान सेवा आप बस @Inject इसे इस तरह CDI का उपयोग कर सकते हैं के लिए एक संदर्भ की जरूरत में:

@Inject PaymentService paymentService; 

ध्यान दें कि निर्माता क्षेत्र को परिभाषित करने से पहले , PaymentService इंजेक्शन सीडीआई मार्ग इंजेक्शन के लिए उपलब्ध नहीं होगा। लेकिन यह हमेशा पुराना तरीका उपलब्ध है। इसके अलावा, किसी भी मामले में वेब सेवा सीडीआई द्वारा प्रबंधित नहीं की जाती है लेकिन निर्माता क्षेत्र को परिभाषित करने से सीडीआई मार्ग इंजेक्शन के लिए बस उस वेब सेवा संदर्भ उपलब्ध कराया जाता है।

+0

आप सीडीआई क्वालिफायर के साथ सादे एनोटेशन भ्रमित कर रहे हैं। हां, सीडीआई क्वालीफायर एनोटेशन हैं, लेकिन सभी एनोटेशन सीडीआई क्वालीफायर नहीं हैं। निर्भरता संकल्प प्रक्रिया में सीडीआई द्वारा विचार किया जाना चाहिए, एक एनोटेशन http://docs.oracle.com/javaee/6/api/javax/inject/Qualifier.html से प्राप्त होना चाहिए। इस प्रकार, @WebServiceRef के साथ निर्माता विधि को एनोटेट करने से सीडीआई के लिए कोई प्रभाव नहीं पड़ता है, क्योंकि यह 'क्वालीफायर' से प्राप्त नहीं होता है। – rdcrng

+0

तो, @ @Pebces @WebServiceRef (लुकअप = "जावा: ऐप/सेवा/भुगतान सेवा") MyWebServiceImpl प्राप्त करें() 'सीडीआई का संबंध है, जहां तक ​​MyWebServiceImpl प्राप्त करें()' के बराबर है। – rdcrng

+0

आप इस सेवा को सीडीआई बीन में कैसे इंजेक्ट करेंगे? हम '@Produces @myservice @WebServiceRef (lookup =" जावा: ऐप/सेवा/भुगतान सेवा ") {} @ इंजेक्ट @ myservice MyWebService का उपयोग करेंगे; 'इस मामले में कंटेनर MyWebServiceImpl जीवन चक्र का प्रबंधन नहीं करता है, यह केवल इसे –

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