मेरा स्प्रिंग @Autowired फ़ील्ड अशक्त क्यों है?


609

नोट: यह एक सामान्य समस्या के लिए विहित उत्तर देने का इरादा है।

मेरे पास एक स्प्रिंग @Serviceक्लास ( MileageFeeCalculator) है जिसमें एक @Autowiredफ़ील्ड ( rateService) है, लेकिन फ़ील्ड nullतब है जब मैं इसका उपयोग करने का प्रयास करता हूं। लॉग से पता चलता है कि MileageFeeCalculatorबीन और बीन दोनों MileageRateServiceबनाए जा रहे हैं, लेकिन NullPointerExceptionजब भी मैं mileageChargeअपनी सेवा बीन पर विधि को कॉल करने की कोशिश करता हूं तो मुझे मिलता है । क्यों वसंत क्षेत्र को स्वाहा नहीं कर रहा है?

नियंत्रक वर्ग:

@Controller
public class MileageFeeController {    
    @RequestMapping("/mileage/{miles}")
    @ResponseBody
    public float mileageFee(@PathVariable int miles) {
        MileageFeeCalculator calc = new MileageFeeCalculator();
        return calc.mileageCharge(miles);
    }
}

सेवा वर्ग:

@Service
public class MileageFeeCalculator {

    @Autowired
    private MileageRateService rateService; // <--- should be autowired, is null

    public float mileageCharge(final int miles) {
        return (miles * rateService.ratePerMile()); // <--- throws NPE
    }
}

सेवा बीन, जिसे स्वतः प्राप्त किया जाना चाहिए, MileageFeeCalculatorलेकिन यह नहीं है:

@Service
public class MileageRateService {
    public float ratePerMile() {
        return 0.565f;
    }
}

जब मैं प्रयास करता GET /mileage/3हूं, मुझे यह अपवाद मिलता है:

java.lang.NullPointerException: null
    at com.chrylis.example.spring_autowired_npe.MileageFeeCalculator.mileageCharge(MileageFeeCalculator.java:13)
    at com.chrylis.example.spring_autowired_npe.MileageFeeController.mileageFee(MileageFeeController.java:14)
    ...

3
एक और परिदृश्य तब हो सकता है जब बीन Fको दूसरे बीन के निर्माता के अंदर बुलाया जाता है S। इस मामले Fमें अन्य सेम Sकंस्ट्रक्टर के लिए एक पैरामीटर के रूप में आवश्यक बीन पास करें और के Sसाथ कंस्ट्रक्टर को एनोटेट करें @Autowire। के Fसाथ पहली बीन के वर्ग को एनोटेट करना याद रखें @Component
अलोपी नोव

मैंने ग्रैडल का उपयोग करते हुए कुछ उदाहरणों को इसी तरह कोडित किया है: github.com/swimorsink/spring-aspectj-examples । उम्मीद है कि कोई इसे उपयोगी पाएगा।
2:11 पर रॉस 117

जवाबों:


648

फ़ील्ड को एनोटेट किया गया @Autowiredहै nullक्योंकि स्प्रिंग को MileageFeeCalculatorआपके द्वारा बनाई गई प्रतिलिपि के बारे में newनहीं पता है और इसे ऑटो करना नहीं जानता था।

स्प्रिंग इनवर्टर ऑफ़ कंट्रोल (IoC) कंटेनर में तीन मुख्य तार्किक घटक होते हैं: एक रजिस्ट्री (जिसे ApplicationContextघटकों के प्रकार (बीन्स) कहा जाता है ) जो अनुप्रयोग द्वारा उपयोग किए जाने के लिए उपलब्ध हैं, एक विन्यासकर्ता प्रणाली जो ऑब्जेक्ट की निर्भरता को मेल करके उन पर निर्भर करती है। संदर्भ में बीन्स के साथ निर्भरताएं, और एक निर्भरता सॉल्वर जो कई अलग-अलग बीन्स के कॉन्फ़िगरेशन को देख सकते हैं और निर्धारित कर सकते हैं कि उन्हें आवश्यक क्रम में कैसे त्वरित और कॉन्फ़िगर किया जाए।

IoC कंटेनर मैजिक नहीं है, और इसमें जावा ऑब्जेक्ट्स के बारे में जानने का कोई तरीका नहीं है जब तक कि आप किसी तरह से इसे सूचित नहीं करते हैं। जब आप कॉल करते हैं new, तो JVM नई ऑब्जेक्ट की एक प्रति को तत्काल भेज देता है और इसे सीधे आपको सौंप देता है - यह कॉन्फ़िगरेशन प्रक्रिया से कभी नहीं जाता है। तीन तरीके हैं जिनसे आप अपने बीन्स को कॉन्फ़िगर कर सकते हैं।

मैंने इस GitHub परियोजना में लॉन्च करने के लिए स्प्रिंग बूट का उपयोग करते हुए इस कोड को पोस्ट किया है ; आप इसे काम करने के लिए आवश्यक हर चीज को देखने के लिए प्रत्येक दृष्टिकोण के लिए एक पूर्ण चल रहे प्रोजेक्ट को देख सकते हैं। इसके साथ टैग करें NullPointerException:nonworking

अपनी फलियों को इंजेक्ट करें

सबसे बेहतर विकल्प यह है कि आप अपने सभी बीन्स को स्प्रिंग ऑटोवेयर करने दें; इसके लिए कम से कम कोड की आवश्यकता होती है और यह सबसे अधिक रखरखाव योग्य है। जैसा आप चाहते थे, उसी MileageFeeCalculatorतरह से ऑटो-फायरिंग का काम करने के लिए :

@Controller
public class MileageFeeController {

    @Autowired
    private MileageFeeCalculator calc;

    @RequestMapping("/mileage/{miles}")
    @ResponseBody
    public float mileageFee(@PathVariable int miles) {
        return calc.mileageCharge(miles);
    }
}

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

टैग जो @MileageFeeCalculatorसेवा ऑब्जेक्ट को इंजेक्ट करके काम करता है :working-inject-bean

@Configurable का उपयोग करें

यदि आपको वास्तव में newस्वत: निर्मित होने वाली वस्तुओं की आवश्यकता है , तो आप अपनी वस्तुओं को इंजेक्ट करने के लिए एस्पेक्टज संकलन-समय की बुनाई के साथ स्प्रिंग @Configurableएनोटेशन का उपयोग कर सकते हैं । यह दृष्टिकोण आपके ऑब्जेक्ट के कंस्ट्रक्टर में कोड सम्मिलित करता है जो स्प्रिंग को अलर्ट करता है कि यह बनाया जा रहा है ताकि स्प्रिंग नए उदाहरण को कॉन्फ़िगर कर सके। इसके लिए आपके बिल्ड में कॉन्फ़िगरेशन की थोड़ी आवश्यकता होती है (जैसे कि संकलन करना ajc) और स्प्रिंग के रनटाइम कॉन्फ़िगरेशन हैंडलर ( @EnableSpringConfiguredJavaConfig सिंटैक्स के साथ ) को चालू करना । इस दृष्टिकोण का उपयोग रूओ एक्टिव रिकॉर्ड सिस्टम द्वारा किया जाता है ताकि newआपकी संस्थाओं को आवश्यक दृढ़ता की जानकारी प्राप्त हो सके।

@Service
@Configurable
public class MileageFeeCalculator {

    @Autowired
    private MileageRateService rateService;

    public float mileageCharge(final int miles) {
        return (miles * rateService.ratePerMile());
    }
}

@Configurableसेवा ऑब्जेक्ट पर उपयोग करके काम करने वाला टैग :working-configurable

मैनुअल बीन लुकअप: अनुशंसित नहीं है

यह दृष्टिकोण केवल विशेष परिस्थितियों में विरासत कोड के साथ हस्तक्षेप करने के लिए उपयुक्त है। एक सिंगलटन एडॉप्टर क्लास बनाने के लिए लगभग हमेशा बेहतर होता है कि स्प्रिंग ऑटोवॉयर कर सकता है और विरासत कोड कॉल कर सकता है, लेकिन बीन के लिए स्प्रिंग एप्लिकेशन संदर्भ को सीधे पूछना संभव है।

ऐसा करने के लिए, आपको एक वर्ग की आवश्यकता होती है, जिसमें स्प्रिंग ApplicationContextवस्तु का संदर्भ दे सके :

@Component
public class ApplicationContextHolder implements ApplicationContextAware {
    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;   
    }

    public static ApplicationContext getContext() {
        return context;
    }
}

तब आपका विरासत कोड कॉल कर सकता है getContext()और इसके लिए आवश्यक सेम प्राप्त कर सकता है:

@Controller
public class MileageFeeController {    
    @RequestMapping("/mileage/{miles}")
    @ResponseBody
    public float mileageFee(@PathVariable int miles) {
        MileageFeeCalculator calc = ApplicationContextHolder.getContext().getBean(MileageFeeCalculator.class);
        return calc.mileageCharge(miles);
    }
}

टैग जो वसंत संदर्भ में मैन्युअल रूप से सेवा ऑब्जेक्ट को देखकर काम करता है: working-manual-lookup


1
दूसरी बात यह है कि सेम में सेम के लिए ऑब्जेक्ट बना रहा है @Configuration, जहां एक विशेष बीन क्लास का एक उदाहरण बनाने की विधि के साथ एनोटेट किया गया है @Bean
डोनल फैलो

@ डोनल फेलो मुझे पूरी तरह से यकीन नहीं है कि आप किस बारे में बात कर रहे हैं ("बनाना" अस्पष्ट है)। क्या आप @Beanस्प्रिंग प्रॉक्सी AOP का उपयोग करते समय कई कॉल के तरीकों की समस्या के बारे में बात कर रहे हैं ?
चिर्लिस -कुट्योपोटेमिमिस्टिक-

1
नमस्ते वहाँ, मैं एक ऐसे ही मुद्दे पर चल रहा हूं, हालांकि जब मैं आपके पहले सुझाव का उपयोग करता हूं, तो "माइलेजफि" विधि को कॉल करते समय मेरा आवेदन "कैल्क" को शून्य लगता है। यह ऐसा है जैसे यह कभी भी प्रारंभिक नहीं करता है @Autowired MileageFeeCalculator calc। कोई विचार?
थियो

मुझे लगता है कि आपको अपने उत्तर के शीर्ष पर एक प्रविष्टि जोड़नी चाहिए जो बताती है कि पहली बीन को पुनः प्राप्त करना, जड़ जिसमें से आप सब कुछ करते हैं, के माध्यम से किया जाना चाहिए ApplicationContext। कुछ उपयोगकर्ता (जिसके लिए मैंने डुप्लिकेट के रूप में बंद कर दिया है) यह समझ में नहीं आता है।
सोतीरियोस डेलिमोलिस

@SotiriosDelimanolis कृपया मुद्दे की व्याख्या करें; मुझे यकीन नहीं है कि आप क्या बिंदु बना रहे हैं।
चिर्लिस -कुट्योपोटेमिमिस्टिक-

59

यदि आप किसी वेब एप्लिकेशन को कोड नहीं कर रहे हैं, तो सुनिश्चित करें कि आपकी कक्षा जिसमें @Autowiring किया गया है, एक स्प्रिंग बीन है। आमतौर पर, स्प्रिंग कंटेनर को उस वर्ग के बारे में पता नहीं होगा जिसे हम स्प्रिंग बीन के रूप में सोच सकते हैं। हमें अपने वसंत वर्गों के बारे में स्प्रिंग कंटेनर को बताना होगा।

इसे appln-contxt में कॉन्फ़िगर करके प्राप्त किया जा सकता है या बेहतर तरीका है वर्ग को @Component के रूप में एनोटेट करें और कृपया नए ऑपरेटर का उपयोग करके एनोटेट वर्ग न बनाएं। सुनिश्चित करें कि आप इसे नीचे दिए गए संदर्भ के रूप में प्राप्त कर सकते हैं।

@Component
public class MyDemo {


    @Autowired
    private MyService  myService; 

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
            System.out.println("test");
            ApplicationContext ctx=new ClassPathXmlApplicationContext("spring.xml");
            System.out.println("ctx>>"+ctx);

            Customer c1=null;
            MyDemo myDemo=ctx.getBean(MyDemo.class);
            System.out.println(myDemo);
            myDemo.callService(ctx);


    }

    public void callService(ApplicationContext ctx) {
        // TODO Auto-generated method stub
        System.out.println("---callService---");
        System.out.println(myService);
        myService.callMydao();

    }

}

नमस्ते, मैं आपके समाधान के माध्यम से चला गया, यह सही है। और यहाँ मैं जानना चाहूंगा "हम नए ऑपरेटर का उपयोग करके एनोटेट वर्ग का उदाहरण क्यों नहीं बनाते हैं, क्या मैं इसके पीछे का कारण जान सकता हूं।
आशीष

3
यदि आप नए का उपयोग करके वस्तु बनाते हैं, तो आप IOC की अवधारणा के विपरीत होने वाले सेम के जीवन चक्र को संभालेंगे। हमें कंटेनर को ऐसा करने के लिए कहने की ज़रूरत है, जो इसे बेहतर तरीके से करता है
शिरीष कूलकर्णी

41

वास्तव में, आपको विधियों को लागू करने के लिए या तो JVM प्रबंधित ऑब्जेक्ट या स्प्रिंग-प्रबंधित ऑब्जेक्ट का उपयोग करना चाहिए। आपके कंट्रोलर क्लास में आपके उपरोक्त कोड से, आप अपने सर्विस क्लास को कॉल करने के लिए एक नई ऑब्जेक्ट बना रहे हैं जिसमें एक ऑटो-वायर्ड ऑब्जेक्ट है।

MileageFeeCalculator calc = new MileageFeeCalculator();

तो यह उस तरह से काम नहीं करेगा।

समाधान इस माइलेजफाइकल्कुलर को नियंत्रक के रूप में एक ऑटो-वायर्ड ऑब्जेक्ट के रूप में बनाता है।

नीचे की तरह अपने नियंत्रक वर्ग को बदलें।

@Controller
public class MileageFeeController {

    @Autowired
    MileageFeeCalculator calc;  

    @RequestMapping("/mileage/{miles}")
    @ResponseBody
    public float mileageFee(@PathVariable int miles) {
        return calc.mileageCharge(miles);
    }
}

4
यह उत्तर है। क्योंकि आप अपने दम पर एक नया MilageFeeCalculator इंस्टेंट कर रहे हैं, इसलिए वसंत तात्कालिकता में शामिल नहीं है, इसलिए वसंत वसंत का कोई ज्ञान नहीं है। इस प्रकार, यह इस पर कुछ भी नहीं कर सकता है, जैसे कि निर्भरता को इंजेक्ट करें।
रॉबर्ट ग्रीथहाउस

26

मुझे एक बार उसी मुद्दे का सामना करना पड़ा जब मैं काफी अभ्यस्त था the life in the IoC world@Autowiredमेरी सेम में से एक के क्षेत्र कार्यावधि में रिक्त है।

मूल कारण यह है कि स्प्रिंग IoC कंटेनर (जिसका @Autowiredक्षेत्र indeedठीक से इंजेक्ट किया गया है) द्वारा बनाए गए ऑटो-निर्मित बीन का उपयोग करने के बजाय , मैं newingउस सेम प्रकार का अपना उदाहरण हूं और इसका उपयोग कर रहा हूं। बेशक यह किसी का @Autowiredक्षेत्र शून्य है क्योंकि स्प्रिंग के पास इसे इंजेक्ट करने का कोई मौका नहीं है।


22

आपकी समस्या नई है (जावा शैली में वस्तु निर्माण)

MileageFeeCalculator calc = new MileageFeeCalculator();

टिप्पणी के साथ @Service, @Component, @Configurationसेम में बनाए जाते हैं
वसंत के आवेदन संदर्भ जब सर्वर शुरू कर दिया है। लेकिन जब हम नए ऑपरेटर का उपयोग करके ऑब्जेक्ट बनाते हैं तो ऑब्जेक्ट को एप्लिकेशन संदर्भ में पंजीकृत नहीं किया जाता है जो पहले से ही बनाया गया है। उदाहरण के लिए Employee.java वर्ग मैंने प्रयोग किया है।

इसकी जांच करें:

public class ConfiguredTenantScopedBeanProcessor implements BeanFactoryPostProcessor {

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    String name = "tenant";
    System.out.println("Bean factory post processor is initialized"); 
    beanFactory.registerScope("employee", new Employee());

    Assert.state(beanFactory instanceof BeanDefinitionRegistry,
            "BeanFactory was not a BeanDefinitionRegistry, so CustomScope cannot be used.");
    BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;

    for (String beanName : beanFactory.getBeanDefinitionNames()) {
        BeanDefinition definition = beanFactory.getBeanDefinition(beanName);
        if (name.equals(definition.getScope())) {
            BeanDefinitionHolder proxyHolder = ScopedProxyUtils.createScopedProxy(new BeanDefinitionHolder(definition, beanName), registry, true);
            registry.registerBeanDefinition(beanName, proxyHolder.getBeanDefinition());
        }
    }
}

}

12

मैं स्प्रिंग के लिए नया हूं, लेकिन मैंने इस काम के समाधान की खोज की। कृपया मुझे बताएं कि क्या यह एक अस्वीकार्य तरीका है।

मैं applicationContextइस बीन में स्प्रिंग इंजेक्शन लगाता हूं :

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class SpringUtils {

    public static ApplicationContext ctx;

    /**
     * Make Spring inject the application context
     * and save it on a static variable,
     * so that it can be accessed from any point in the application. 
     */
    @Autowired
    private void setApplicationContext(ApplicationContext applicationContext) {
        ctx = applicationContext;       
    }
}

आप चाहें तो इस कोड को मुख्य एप्लिकेशन वर्ग में भी डाल सकते हैं।

अन्य वर्ग इसका उपयोग इस तरह कर सकते हैं:

MyBean myBean = (MyBean)SpringUtils.ctx.getBean(MyBean.class);

इस तरह से किसी भी बीन को किसी भी वस्तु के द्वारा आवेदन में प्राप्त किया जा सकता है (साथ ही साथ new) और स्थिर तरीके से


1
वसंत पैटर्न को विरासत कोड तक पहुंच बनाने के लिए यह पैटर्न आवश्यक है लेकिन नए कोड में इसे टाला जाना चाहिए।
चिरलीस -कुट्टोप्टोमिस्टिक-

2
आप वसंत के लिए नए नहीं हैं। आप एक समर्थक हैं। :)
चिकित्सा

आपने मुझे बचाया ...
गोविंद सिंह

मेरे मामले में मुझे इसकी आवश्यकता थी क्योंकि कुछ तीसरे पक्ष के वर्ग थे। स्प्रिंग (IOC) का उन पर नियंत्रण नहीं था। इन कक्षाओं को मेरे स्प्रिंग बूट ऐप से कभी नहीं बुलाया गया। मैंने इस दृष्टिकोण का पालन किया और इसने मेरे लिए काम किया।
जोगिंदर मलिक

12

यह दुर्लभ मामला लगता है लेकिन यहाँ मेरे साथ क्या हुआ है:

हमने इसका उपयोग किया जिसकी @Injectबजाय @Autowiredस्प्रिंग द्वारा समर्थित जावाई मानक है। हर जगह यह ठीक काम करता है और सेम एक जगह के बजाय सही तरीके से इंजेक्ट किया जाता है। सेम इंजेक्शन एक ही लगता है

@Inject
Calculator myCalculator

अंत में हमने पाया कि त्रुटि यह थी कि हम (वास्तव में, ग्रहण ऑटो पूर्ण सुविधा) के com.opensymphony.xwork2.Injectबजाय आयात किया गया थाjavax.inject.Inject !

तो सुनिश्चित करें कि आपके एनोटेशन (संक्षेप में प्रस्तुत करने, मेकअप @Autowired, @Inject, @Service, ...) सही संकुल है!


5

मुझे लगता है कि आप एनोटेशन के साथ कक्षाओं को स्कैन करने के लिए वसंत को निर्देश देने से चूक गए हैं।

आप @ComponentScan("packageToScan")वसंत को स्कैन करने के लिए निर्देश देने के लिए अपने वसंत आवेदन के विन्यास वर्ग पर उपयोग कर सकते हैं ।

@Service, @Component आदि एनोटेशन मेटा विवरण जोड़ते हैं।

वसंत केवल उन वर्गों के उदाहरणों को इंजेक्ट करता है जो या तो सेम के रूप में बनाए जाते हैं या एनोटेशन के साथ चिह्नित होते हैं।

एनोटेशन के साथ चिह्नित वर्गों को इंजेक्शन लगाने से पहले वसंत द्वारा पहचाना जाना चाहिए, @ComponentScanएनोटेशन के साथ चिह्नित कक्षाओं के लिए स्प्रिंग लुक का निर्देश दें। जब वसंत को @Autowiredयह संबंधित बीन की खोज करता है, और आवश्यक उदाहरण को इंजेक्ट करता है।

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


इस में भाग गया जब मैं <context:component-scan base-package="com.mypackage"/>अपनी beans.xmlफ़ाइल में जोड़ना भूल गया
राल्फ कॉलवे

5

यदि यह एक परीक्षण वर्ग में हो रहा है, तो सुनिश्चित करें कि आप कक्षा को एनोटेट करना नहीं भूले हैं।

उदाहरण के लिए, स्प्रिंग बूट में :

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTests {
    ....

कुछ समय बीत गया ...

स्प्रिंग बूट का विकास जारी है@RunWith यदि आप JUnit के सही संस्करण का उपयोग करते हैं तो इसका उपयोग करने की आवश्यकता नहीं है ।

@SpringBootTestअकेले काम करने के लिए, आपको JUnit4 के बजाय JUnit5@Test से उपयोग करने की आवश्यकता है ।

//import org.junit.Test; // JUnit4
import org.junit.jupiter.api.Test; // JUnit5

@SpringBootTest
public class MyTests {
    ....

यदि आप इस कॉन्फ़िगरेशन को गलत पाते हैं तो आपके परीक्षण संकलित होंगे, लेकिन @Autowiredऔर @Valueफ़ील्ड्स (उदाहरण के लिए) होंगे null। चूंकि स्प्रिंग बूट जादू द्वारा संचालित होता है, इसलिए इस विफलता को सीधे डीबग करने के लिए आपके पास कुछ रास्ते हो सकते हैं।


इन्हें भी देखें: stackoverflow.com/questions/4130486/…
nobar

नोट: खेतों के @Valueसाथ उपयोग किए जाने पर अशक्त हो जाएगा static
नोबार

वसंत विफल होने के कई तरीके प्रदान करता है (संकलक की कोई मदद नहीं)। जब चीजें गलत हो जाती हैं, तो आपका सबसे अच्छा दांव वर्ग एक पर लौटना है - केवल एनोटेशन के संयोजन का उपयोग करना जो आपको पता है कि एक साथ काम करेंगे।
नोबार

4

एक और समाधान कॉल करना होगा: SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)
माइलेजफाइकल्कर निर्माता को इस तरह से:

@Service
public class MileageFeeCalculator {

    @Autowired
    private MileageRateService rateService; // <--- will be autowired when constructor is called

    public MileageFeeCalculator() {
        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)
    }

    public float mileageCharge(final int miles) {
        return (miles * rateService.ratePerMile()); 
    }
}

यह असुरक्षित प्रकाशन का उपयोग करता है।
चिरलीस -कुट्टोप्टोमाइस्टिक-

3

अद्यतन: वास्तव में स्मार्ट लोग इस पर इंगित करने के लिए जल्दी थे उत्तर , जो नीचे वर्णित अजीबता की व्याख्या करता है

मूल ANSWER:

मुझे नहीं पता कि यह किसी की मदद करता है, लेकिन मैं चीजों को सही ढंग से करते हुए भी उसी समस्या से घिरा हुआ था। मेरी मुख्य विधि में, मेरे पास एक कोड है:

ApplicationContext context =
    new ClassPathXmlApplicationContext(new String[] {
        "common.xml",
        "token.xml",
        "pep-config.xml" });
    TokenInitializer ti = context.getBean(TokenInitializer.class);

और एक token.xmlफाइल में मेरे पास एक लाइन है

<context:component-scan base-package="package.path"/>

मैंने देखा कि package.path अब मौजूद नहीं है, इसलिए मैंने सिर्फ अच्छे के लिए लाइन को गिरा दिया है।

और उसके बाद, एनपीई में आना शुरू हुआ। pep-config.xmlमेरे पास सिर्फ 2 सेम थे:

<bean id="someAbac" class="com.pep.SomeAbac" init-method="init"/>
<bean id="settings" class="com.pep.Settings"/>

और SomeAbac वर्ग के पास घोषित संपत्ति है

@Autowired private Settings settings;

किसी अज्ञात कारण के लिए, सेटिंग्स init () में शून्य है, जब <context:component-scan/>तत्व बिल्कुल मौजूद नहीं है, लेकिन जब यह मौजूद है और आधार बेस के रूप में कुछ bs है, तो सब कुछ अच्छी तरह से काम करता है। यह रेखा अब इस तरह दिखती है:

<context:component-scan base-package="some.shit"/>

और यह काम करता है। कोई व्यक्ति स्पष्टीकरण दे सकता है, लेकिन मेरे लिए अभी यह पर्याप्त है)


5
वह उत्तर स्पष्टीकरण है। कार्य करने के लिए आवश्यक <context:component-scan/>रूप से सक्षम बनाता <context:annotation-config/>है @Autowired
ForNeVeR

3

यह NullPointerException देने का अपराधी है MileageFeeCalculator calc = new MileageFeeCalculator();हम स्प्रिंग का उपयोग कर रहे हैं - मैन्युअल रूप से ऑब्जेक्ट बनाने की आवश्यकता नहीं है। IoC कंटेनर द्वारा ऑब्जेक्ट निर्माण का ध्यान रखा जाएगा।


2

आप इस समस्या को सेवा वर्ग पर @Service एनोटेशन का उपयोग करके भी ठीक कर सकते हैं और अन्य सेम क्लासबी कंस्ट्रक्टर के पैरामीटर के रूप में आवश्यक बीन क्लासए पास कर सकते हैं और @Autowired के साथ क्लासबी के निर्माता को एनोटेट कर सकते हैं। नमूना स्निपेट यहां:

@Service
public class ClassB {

    private ClassA classA;

    @Autowired
    public ClassB(ClassA classA) {
        this.classA = classA;
    }

    public void useClassAObjectHere(){
        classA.callMethodOnObjectA();
    }
}

यह मेरे लिए काम कर रहा है बू टी क्या आप इस मुद्दे को हल कर रहे हैं पर विस्तृत कर सकते हैं?
क्रुएलजाइन 12

1
@CruelEngine, यह देखें कि इंजेक्शन इंजेक्शन है (जहां आप स्पष्ट रूप से एक ऑब्जेक्ट सेट कर रहे हैं) केवल फील्ड इंजेक्शन का उपयोग करने के बजाय (यह ज्यादातर वसंत कॉन्फ़िगरेशन द्वारा किया जाता है)। इसलिए यदि आप "नया" ऑपरेटर का उपयोग करके ClassB की एक वस्तु बना रहे हैं, तो कुछ और गुंजाइश है, जो कि ClassA के लिए दृश्यमान या स्वतः निर्धारित नहीं होगा। इसलिए, जबकि classB.useClassAObjectHere () एनपीई को फेंक देंगे क्योंकि क्लास ए ऑब्जेक्ट को ऑटोलर्ड नहीं किया गया था यदि आप सिर्फ फील्ड इंजेक्शन की घोषणा करते हैं। पढ़ें chrylis एक ही समझाने की कोशिश कर रहा है। और यही कारण है कि फील्ड इंजेक्शन पर कंस्ट्रक्टर इंजेक्शन की सिफारिश की जाती है। क्या यह अब समझ में आता है?
अभिषेक

1

यहाँ जो उल्लेख नहीं किया गया है वह इस लेख में "निष्पादन के आदेश" के अनुच्छेद में वर्णित है ।

"सीखने" के बाद, मुझे @Component या डेरिवेटिव @Service या @Repository के साथ एक वर्ग को एनोटेट करना था (मुझे लगता है कि वहाँ अधिक हैं), उनके अंदर अन्य घटकों को स्वत: प्राप्त करने के लिए, इसने मुझे मारा कि ये अन्य घटक अभी भी कंस्ट्रक्टर के अंदर शून्य थे। मूल घटक की।

@PostConstruct का उपयोग करके हल करता है:

@SpringBootApplication
public class Application {
    @Autowired MyComponent comp;
}

तथा:

@Component
public class MyComponent {
    @Autowired ComponentDAO dao;

    public MyComponent() {
        // dao is null here
    }

    @PostConstruct
    public void init() {
        // dao is initialized here
    }
}

1

यह केवल यूनिट परीक्षण के मामले में मान्य है।

मेरे सेवा वर्ग में सेवा का @autowiredएक विवरण था और यह एक अन्य घटक वर्ग था। जब मैंने परीक्षण किया तो घटक वर्ग अशक्त आ रहा था। क्योंकि सर्विस क्लास के लिए मैं ऑब्जेक्ट का उपयोग करके बना रहा थाnew

यदि आप यूनिट टेस्ट लिख रहे हैं तो सुनिश्चित करें कि आप ऑब्जेक्ट का उपयोग नहीं कर रहे हैं new object()। इसके बजाय इंजेक्टमॉक का उपयोग करें।

इससे मेरा मुद्दा ठीक हो गया। यहाँ एक उपयोगी लिंक है


0

यह भी ध्यान रखें कि अगर, किसी भी कारण, आप एक में एक विधि बनाने के @Serviceरूप में final, autowired सेम आप का उपयोग करेंगे यह हमेशा हो जाएगा से null


0

सरल शब्दों में किसी @Autowiredक्षेत्र के होने के मुख्यतः दो कारण हैंnull

  • आपकी कक्षा एक वसंत से पहले नहीं है।

  • FIELD एक BEAN नहीं है।


0

पूरी तरह से सवाल से संबंधित नहीं है, लेकिन यदि फ़ील्ड इंजेक्शन शून्य है, तो निर्माण आधारित इंजेक्शन अभी भी ठीक काम करेगा।

    private OrderingClient orderingClient;
    private Sales2Client sales2Client;
    private Settings2Client settings2Client;

    @Autowired
    public BrinkWebTool(OrderingClient orderingClient, Sales2Client sales2Client, Settings2Client settings2Client) {
        this.orderingClient = orderingClient;
        this.sales2Client = sales2Client;
        this.settings2Client = settings2Client;
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.