वसंत (कब निर्भरता इंजेक्शन का उपयोग करने के लिए) द्वारा कौन से वर्गों को स्वत: बंद कर दिया जाना चाहिए?


32

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

और मैं @Autowired एनोटेशन, XML कॉन्फ़िगरेशन, सेटर इंजेक्शन, कंस्ट्रक्टर इंजेक्शन, आदि के बीच मतभेदों के बारे में बात नहीं करना चाहता। मेरा सवाल एक सामान्य है।

मान लें कि हमारे पास एक कनवर्टर के साथ एक सेवा है:

@Service
public class Service {

    @Autowired
    private Repository repository;

    @Autowired
    private Converter converter;

    public List<CarDto> getAllCars() {
        List<Car> cars = repository.findAll();
        return converter.mapToDto(cars);
    }
}

@Component
public class Converter {

    public CarDto mapToDto(List<Car> cars) {
        return new ArrayList<CarDto>(); // do the mapping here
    }
}

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

@Service
public class Service {

    @Autowired
    private Repository repository;

    public List<CarDto> getAllCars() {
        List<Car> cars = repository.findAll();
        Converter converter = new Converter();
        return converter.mapToDto(cars);
    }
}

अब इसे परखना ज्यादा कठिन है। इसके अलावा, हर कन्वर्टर ऑपरेशन के लिए नया कन्वर्टर बनाया जाएगा, भले ही वह हमेशा एक ही स्थिति में हो, जो ओवरहेड जैसा लगता है।

स्प्रिंग एमवीसी में कुछ प्रसिद्ध पैटर्न हैं: रिपॉजिटरी का उपयोग करके सेवाओं और सेवाओं का उपयोग करने वाले नियंत्रक। फिर, यदि रिपॉजिटरी को ऑटोवॉयर किया जाता है (जो कि आमतौर पर होता है), तो सर्विस को भी ऑटोवॉयर करना पड़ता है। और यह काफी स्पष्ट है। लेकिन हम @Component एनोटेशन का उपयोग कब करते हैं? यदि आपके पास कुछ स्थिर उपयोग कक्षाएं (जैसे कन्वर्टर्स, मैपर्स) हैं - तो क्या आप उन्हें ऑटो करते हैं?

क्या आप सभी वर्गों को स्वावलंबी बनाने की कोशिश करते हैं? फिर सभी वर्ग निर्भरताएं इंजेक्ट करना आसान है (एक बार फिर से, समझने में आसान और परीक्षण करने में आसान)। या क्या आप केवल तभी ऑटो करना चाहते हैं जब यह बिल्कुल आवश्यक हो?

मैंने कुछ समय बिताया है जब ऑटोवायरिंग का उपयोग करने के लिए कुछ सामान्य नियमों की तलाश की गई थी, लेकिन मुझे कोई विशेष सुझाव नहीं मिला। आमतौर पर, लोग "क्या आप DI का उपयोग करते हैं? (हां / नहीं)" या "आप किस प्रकार की निर्भरता इंजेक्शन पसंद करते हैं" के बारे में बात करते हैं, जो मेरे सवाल का जवाब नहीं देता है।

मैं इस विषय से संबंधित किसी भी सुझाव के लिए आभारी रहूंगा!


3
+1 अनिवार्य रूप से "जब यह बहुत दूर जा रहा है?"
एंडी हंट

जवाबों:


8

@ EricW की टिप्पणी से सहमत हैं, और बस यह याद रखना चाहते हैं कि आप अपने कोड को रखने के लिए इनिशियलाइज़र का उपयोग कर सकते हैं:

@Autowired
private Converter converter;

या

private Converter converter = new Converter();

या, अगर वर्ग वास्तव में कोई राज्य नहीं है

private static final Converter CONVERTER = new Converter();

इसके लिए एक महत्वपूर्ण मानदंड है कि क्या स्प्रिंग को बीन को तुरंत इंजेक्ट और इंजेक्ट करना चाहिए, क्या यह बीन इतना जटिल है कि आप इसे परीक्षण में मॉक करना चाहते हैं? यदि ऐसा है, तो इसे इंजेक्ट करें। उदाहरण के लिए, यदि कनवर्टर किसी बाहरी प्रणाली के लिए एक गोल यात्रा करता है, तो इसे इसके बजाय एक घटक बनाएं। या यदि रिटर्न वैल्यू में इनपुट के आधार पर दर्जनों संभावित बदलावों के साथ एक बड़ा निर्णय ट्री है, तो इसे मॉक करें। इत्यादि।

आपने पहले से ही उस कार्यक्षमता को रोल करने और उसे एनकैप्सुलेट करने का एक अच्छा काम किया है, इसलिए अब यह सिर्फ एक सवाल है कि क्या यह परीक्षण के लिए एक अलग "इकाई" माना जाना जटिल है।


5

मुझे नहीं लगता कि आपको अपनी सभी कक्षाओं के बारे में @ सूचित करना होगा, यह वास्तविक उपयोग पर निर्भर होना चाहिए, आपके परिदृश्यों के लिए @Autowired के बजाय स्थैतिक विधि का बेहतर उपयोग होना चाहिए। मुझे उन साधारण बर्तनों के वर्ग के लिए कोई भी लाभ @ उपयोग नहीं मिला है, और अगर यह ठीक से उपयोग नहीं करता है, तो वसंत कंटेनर की लागत में पूरी तरह से वृद्धि होगी।


2

मेरे अंगूठे का नियम कुछ इस बात पर आधारित है कि आपने क्या कहा: परीक्षण करने योग्य। अपने आप से पूछें " क्या मैं यूनिट आसानी से इसका परीक्षण कर सकता हूं? "। अगर जवाब हां है, तो किसी अन्य कारण के अभाव में मैं इसके साथ ठीक हो जाऊंगा। इसलिए, यदि आप एक ही समय में यूनिट टेस्ट विकसित कर रहे हैं तो आप बहुत दर्द से बचाएंगे।

एकमात्र संभावित समस्या यह है कि यदि कनवर्टर विफल हो जाता है तो आपकी सेवा परीक्षा भी विफल हो जाएगी। कुछ लोग कहेंगे कि आपको यूनिट परीक्षणों में कनवर्टर के परिणामों का मजाक बनाना चाहिए। इस तरह आप त्रुटियों फास्टर्स की पहचान करने में सक्षम होंगे। लेकिन इसकी एक कीमत है: आपको सभी कन्वर्टर्स परिणामों का मजाक उड़ाना होगा जब असली कनवर्टर काम कर सकता था।

मैं यह भी मानता हूं कि अलग-अलग dto कन्वर्टर्स का उपयोग करने का कोई कारण नहीं है।


0

टीएल; डीआर: डीआई के लिए ऑटोराइरिंग का एक संकर दृष्टिकोण, और डीआई के लिए निर्माणकर्ता आपके द्वारा प्रस्तुत कोड को सरल बना सकता है।

मैं स्प्रिंग फ्रेमवर्क स्टार्टअप त्रुटियों / जटिलताओं के साथ कुछ वेबलॉग के कारण इसी तरह के सवालों को देख रहा हूं जिसमें @autowired बीन इनिशियलाइज़ेशन निर्भरता शामिल है। मैं एक और DI दृष्टिकोण में मिश्रण शुरू कर दिया है: निर्माता अग्रेषण। इसके लिए आपके पास मौजूद शर्तों की आवश्यकता होती है ("स्पष्ट रूप से, कनवर्टर की कोई निर्भरता नहीं है, इसलिए यह आवश्यक नहीं है कि यह स्वतः-लोड हो।")। फिर भी, मैं लचीलेपन के लिए बहुत पसंद करता हूं और यह अभी भी बहुत सीधा है।

@Service
public class Service {

    @Autowired
    private Repository repository;

    public List<CarDto> getAllCars(Converter converter) {
        List<Car> cars = repository.findAll();
        return converter.mapToDto(cars);
    }
    public List<CarDto> getAllCars() {
        Converter converter = new Converter();
        return getAllCars(converter);
    }
}

या रोब के जवाब से एक राइफ के रूप में भी

@Service
public class Service {

    @Autowired
    private Repository repository;

    private final Converter converter = new Converter(); // static if safe for that

    public List<CarDto> getAllCars(Converter converter) {
        List<Car> cars = repository.findAll();
        return converter.mapToDto(cars);
    }
    public List<CarDto> getAllCars() {
        return getAllCars(converter);
    }
}

इसे सार्वजनिक इंटरफ़ेस परिवर्तन की आवश्यकता नहीं हो सकती है लेकिन मैं करूँगा। अभी भी

public List<CarDto> getAllCars(Converter converter) { ... }

केवल परीक्षण प्रयोजनों / विस्तार के लिए गुंजाइश के लिए संरक्षित या निजी बनाया जा सकता है।

प्रमुख बिंदु यह है कि DI वैकल्पिक है। एक डिफ़ॉल्ट प्रदान किया जाता है, जिसे सीधे आगे तरीके से ओवरराइड किया जा सकता है। खेतों की संख्या में वृद्धि के रूप में इसकी कमजोरी है, लेकिन 1, शायद 2 क्षेत्रों के लिए, मैं इसे निम्नलिखित परिस्थितियों में पसंद करूंगा:

  • बहुत कम संख्या में खेत
  • डिफ़ॉल्ट लगभग हमेशा उपयोग किया जाता है (DI एक परीक्षण सीम है) या डिफ़ॉल्ट का उपयोग लगभग कभी नहीं किया जाता है (स्टॉप गैप) क्योंकि मुझे निरंतरता पसंद है, इसलिए यह मेरे फैसले के पेड़ का हिस्सा है, न कि एक सच्चे डिजाइन की कमी

अंतिम बिंदु (एक बिट ओटी, लेकिन हम कैसे / जहां @ अनधिकृत का फैसला करते हैं) से संबंधित: प्रस्तुतकर्ता वर्ग, जैसा कि प्रस्तुत किया गया है, उपयोगिता विधि है (कोई फ़ील्ड नहीं, कोई निर्माता, स्थिर नहीं हो सकता)। हो सकता है कि समाधान कार वर्ग में कुछ प्रकार के मैपटूडो () पद्धति का हो? यही है, कारों की परिभाषा में रूपांतरण इंजेक्शन को धक्का दें, जहां संभवतः पहले से ही बंधे होने की संभावना है:

@Service
public class Service {

   @Autowired
   private Repository repository;

   public List<CarDto> getAllCars() {
    return repository.findAll().stream.map(c -> c.mapToDto()).collect(Collectors.toList()));
   }
}

-1

मुझे लगता है कि इसका एक अच्छा उदाहरण SecurityUtils या UserUtils जैसा है। किसी भी स्प्रिंग ऐप के साथ, जो उपयोगकर्ताओं को प्रबंधित करता है, आपको कुछ यूटील क्लास की आवश्यकता होगी जिसमें पूरे स्टैटिक तरीके हों जैसे:

getCurrentUser ()

isAuthenticated ()

isCurrentUserInRole (प्राधिकरण प्राधिकरण)

आदि।

और मैंने कभी भी इन्हें स्वीकार नहीं किया। JHipster (जो मैं सबसे अच्छे अभ्यास के एक बहुत अच्छे न्यायाधीश के रूप में उपयोग करता हूं) नहीं करता है।


-2

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


3
यह पोस्ट पढ़ना मुश्किल है (पाठ की दीवार)। क्या आप इसे बेहतर आकार में संपादित करना चाहेंगे ?
gnat
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.