আমার বসন্ত @ অটোভায়ার্ড ক্ষেত্রটি নাল কেন?


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
aliopi

আমি এখানে গ্র্যাডল ব্যবহার করে এর সাথে খুব একই রকম কয়েকটি উদাহরণ কোড আপ করেছি: github.com/swimorsink/spring-aspectj- উদাহরণ । আশা করি কেউ এটি কাজে লাগবে।
রস 117

উত্তর:


648

বর্ণিত ক্ষেত্রটি @Autowiredহ'ল nullকারণ স্প্রিং MileageFeeCalculatorআপনার দ্বারা তৈরি করা অনুলিপি সম্পর্কে newজানেন না এবং এটি স্বায়ত্তশাসিত করতে জানেন না।

স্প্রিং ইনভার্সন অফ কন্ট্রোল (আইওসি) ধারকটির তিনটি প্রধান যৌক্তিক উপাদান রয়েছে: ApplicationContextঅ্যাপ্লিকেশন ব্যবহার করার জন্য উপলব্ধ উপাদানগুলির (রেস) নামে একটি রেজিস্ট্রি , একটি কনফিগার সিস্টেম যা মিলিয়ে তাদের মধ্যে বস্তুর নির্ভরতা ইনজেক্ট করে the প্রসঙ্গে শিমের সাথে নির্ভরতা এবং একটি নির্ভরতা সমাধানকারী যা বিভিন্ন বিভিন্ন মটরশুটির একটি কনফিগারেশন দেখে এবং কীভাবে তাদের প্রয়োজনীয় ক্রমে ইনস্ট্যান্টিয়েট এবং কনফিগার করতে হয় তা নির্ধারণ করতে পারে।

আইওসি পাত্রে যাদু নয় এবং জাভা অবজেক্টগুলি সম্পর্কে জানার কোনও উপায় নেই আপনি যদি কোনওভাবে সেগুলি অবহিত না করেন। আপনি যখন কল করবেন new, জেভিএম নতুন বস্তুর একটি অনুলিপি ইনস্ট্যান্ট করে সরাসরি আপনার হাতে দেয় - এটি কখনই কনফিগারেশন প্রক্রিয়াটির মধ্য দিয়ে যায় না। তিনটি উপায় রয়েছে যে আপনি আপনার মটরশুটি কনফিগার করতে পারেন।

আমি এই গিটহাব প্রকল্পে স্প্রিং বুট ব্যবহার করে এই কোডের সমস্ত পোস্ট করেছি ; আপনার এটিকে কার্যকর করার জন্য প্রয়োজনীয় সমস্ত কিছু দেখতে প্রতিটি পদ্ধতির জন্য আপনি একটি সম্পূর্ণ চলমান প্রকল্পটি দেখতে পারেন। এর সাথে ট্যাগ করুন 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

@ কনফিগারযোগ্য ব্যবহার করুন

আপনার যদি সত্যই newঅটোওয়ার্ড হওয়ার সাথে সাথে তৈরি জিনিসগুলির প্রয়োজন হয় তবে আপনি আপনার অবজেক্টগুলি ইনজেক্ট করার জন্য এস্পেক্টজে সংকলন-সময় বুননের পাশাপাশি স্প্রিং @Configurableটীকাটি ব্যবহার করতে পারেন । এই পদ্ধতিটি আপনার অবজেক্টের কনস্ট্রাক্টরে কোড প্রবেশ করায় যা স্প্রিংকে তৈরি করে যা সতর্ক করে দেয় যাতে স্প্রিং নতুন উদাহরণটি কনফিগার করতে পারে। এটির জন্য আপনার বিল্ডে কিছুটা কনফিগারেশন প্রয়োজন (যেমন সংকলন করা ajc) এবং স্প্রিংয়ের রানটাইম কনফিগারেশন হ্যান্ডলারগুলি চালু করা ( @EnableSpringConfiguredজাভা কনফিগ সিনট্যাক্স সহ)। এই সক্রিয়করণটি রু অ্যাক্টিভ রেকর্ড সিস্টেম দ্বারা newআপনার সত্তাগুলির দৃষ্টান্তগুলি প্রয়োজনীয় জেদী তথ্য ইনজেকশনের অনুমতি দেয় is

@Service
@Configurable
public class MileageFeeCalculator {

    @Autowired
    private MileageRateService rateService;

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

ট্যাগ যা @Configurableপরিষেবা অবজেক্টে ব্যবহার করে কাজ করে :working-configurable

ম্যানুয়াল বিন সন্ধান: প্রস্তাবিত নয়

এই পদ্ধতির বিশেষ পরিস্থিতিতে লেগ্যাসি কোডের সাথে ইন্টারফেস করার জন্য উপযুক্ত। একটি সিঙ্গলটন অ্যাডাপ্টার শ্রেণি তৈরি করা প্রায় সবসময়ই ভাল Spring

এটি করার জন্য, আপনার একটি শ্রেণীর প্রয়োজন যেখানে স্প্রিং 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স্প্রিং প্রক্সি এওপি ব্যবহার করার সময় আপনি কি একাধিক কল পদ্ধতিতে সমস্যা নিয়ে কথা বলছেন ?
ক্রাইলিস -কোটিরিওপটিস্টিস্টিক-

1
হাই, আমি একই ধরণের সমস্যায় পড়ছি, তবে আমি যখন আপনার প্রথম পরামর্শটি ব্যবহার করি তখন আমার অ্যাপ্লিকেশনটি "মাইলেজফাই" পদ্ধতিটি কল করার সময় "ক্যালক" বাতিল বলে মনে করে। এটি যেন কখনও সূচনা করে না @Autowired MileageFeeCalculator calc। কোন চিন্তা?
থিও

আমি মনে করি আপনার উত্তরের উপরের অংশে আপনার একটি এন্ট্রি যুক্ত করা উচিত যা ব্যাখ্যা করে যে প্রথম শিমটি, যেটি থেকে আপনি সমস্ত কিছু করেন তার পুনরুদ্ধার, এর মাধ্যমে করা উচিত ApplicationContext। কিছু ব্যবহারকারী (যার জন্য আমি সদৃশ হিসাবে বন্ধ করেছি) এটি বুঝতে পারে না।
সোটিরিওস ডেলিমনলিস

@ সোটিরিওস ডেলিমনোলিস দয়া করে বিষয়টি ব্যাখ্যা করুন; আপনি ঠিক কী পয়েন্ট তৈরি করছেন তা আমি নিশ্চিত নই।
ক্রাইলিস -কোটিরিওপোস্টিস্টিক-

59

যদি আপনি কোনও ওয়েব অ্যাপ্লিকেশন কোডিং না করে থাকেন তবে নিশ্চিত হন যে আপনার ক্লাসটি যেখানে @ অটোয়ারিং করা হচ্ছে এটি একটি বসন্ত বিন। সাধারণত, বসন্ত ধারক ক্লাস সম্পর্কে সচেতন হবে না যা আমরা একটি বসন্ত শিম হিসাবে ভাবতে পারি। আমাদের বসন্তের ক্লাসগুলি সম্পর্কে আমাদের স্প্রিং পাত্রে বলতে হবে।

এটি অ্যাপ্লিন-কনটেক্সটে কনফিগার করার মাধ্যমে অর্জন করা যেতে পারে বা আরও ভাল উপায় হ'ল @ কম্পোনেন্ট হিসাবে ক্লাসটি বেনিফিট করা এবং দয়া করে নতুন অপারেটর ব্যবহার করে টীকাগুলি শ্রেণি তৈরি করবেন না। নিশ্চিত হয়ে নিন যে আপনি এটি নীচের মত অ্যাপ্লিন-প্রসঙ্গ থেকে পেয়েছেন।

@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
আপনি যদি নতুনটি ব্যবহার করে অবজেক্টটি তৈরি করেন তবে আপনি শিমের জীবনচক্র পরিচালনা করছেন যা আইওসি-র ধারণার বিরোধী। আমাদের
ধারককে

41

প্রকৃতপক্ষে, পদ্ধতিগুলি আহ্বানের জন্য আপনার জেভিএম পরিচালিত অবজেক্ট বা স্প্রিং-পরিচালিত অবজেক্টটি ব্যবহার করা উচিত। আপনার নিয়ামক শ্রেণীর উপরের কোড থেকে আপনি নিজের পরিষেবা শ্রেণিকে কল করতে একটি নতুন অবজেক্ট তৈরি করছেন যা একটি স্বয়ংক্রিয়-ওয়্যার্ড অবজেক্ট রয়েছে।

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
এই উত্তর। যেহেতু আপনি নিজেরাই একটি নতুন মিলেজফাইক্যালকুলেটর ইনস্ট্যান্ট করছেন, বসন্ত তাত্ক্ষণিকতায় জড়িত নয়, তাই স্প্রিং স্প্রিংয়ের কোনও অজানা নেই knowledge সুতরাং, এটি কিছুতেই করতে পারে না, যেমন ইনজেকশন নির্ভরতা।
রবার্ট গ্রেটহাউস

26

আমি একবারে একই সমস্যার মুখোমুখি হয়েছি যখন আমার বেশ অভ্যস্ত ছিল না the life in the IoC world@Autowiredআমার মটরশুটি এক ক্ষেত্র রানটাইম এ নাল হয়।

মূল কারণটি হ'ল স্প্রিং আইওসি পাত্রে (যার @Autowiredক্ষেত্রটি indeedযথাযথভাবে ইনজেকশন করা হয়) দ্বারা পরিচালিত স্বয়ংক্রিয়ভাবে তৈরি শিমটি ব্যবহার করার পরিবর্তে আমি newingসেই শিমের ধরণের আমার নিজস্ব উদাহরণ এবং এটি ব্যবহার করছি। অবশ্যই @Autowiredএটির ক্ষেত্রটি শূন্য কারণ স্প্রিংয়ের এটিতে ইনজেকশনের কোনও সুযোগ নেই।


22

আপনার সমস্যাটি নতুন (জাভা শৈলীতে বস্তু তৈরি)

MileageFeeCalculator calc = new MileageFeeCalculator();

টীকা দিয়ে @Service, @Component, @Configurationমটরশুটি মধ্যে নির্মিত
বসন্তের আবেদন প্রেক্ষাপটে যখন সার্ভার আরম্ভ করা হয়। কিন্তু যখন আমরা নতুন অপারেটর ব্যবহার করে বস্তুগুলি তৈরি করি তখন বস্তুটি ইতিমধ্যে তৈরি হওয়া প্রয়োগের প্রসঙ্গে নিবন্ধভুক্ত নয়। উদাহরণ হিসাবে আমি কর্মচারী.জভা ক্লাস ব্যবহার করেছি।

এটা দেখ:

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
আপনি বসন্তে নতুন নন। আপনি একজন প্রো। :)
sapy

আপনি আমাকে বাঁচিয়েছেন ...
গোবিন্দ সিং

আমার ক্ষেত্রে আমার এটি প্রয়োজন ছিল কারণ এখানে তৃতীয় পক্ষের কয়েকটি ক্লাস ছিল। বসন্তের (আইওসি) তাদের উপর নিয়ন্ত্রণ ছিল না। এই ক্লাসগুলি কখনই আমার বসন্ত বুট অ্যাপ থেকে কল করা হয়নি। আমি এই পদ্ধতির অনুসরণ করেছি এবং এটি আমার পক্ষে কাজ করেছে।
জোগিন্দার মালিক

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
নভেম্বর

বসন্ত ব্যর্থ হওয়ার অসংখ্য উপায় সরবরাহ করে (সংকলকটির সাহায্য ছাড়াই)। যখন জিনিসগুলি ভুল হয়ে যায়, আপনার সেরা বাজি হ'ল স্কোয়ার ওয়ানে ফিরে আসুন - আপনি যে টীকাগুলি জানেন তা কেবল একসাথে কাজ করবে using
নভেম্বর

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

আপডেট: সত্যই স্মার্ট লোকেরা নীচে বর্ণিত অদ্ভুততার ব্যাখ্যা দেয় এই উত্তরটির বিষয়ে দ্রুত নির্দেশ করেছিল

মূল উত্তর:

আমি জানি না এটি কারও সাহায্য করে কিনা, তবে জিনিসগুলি আপাতদৃষ্টিতে সঠিকভাবে করার সময়ও আমি একই সমস্যার সাথে আটকে ছিলাম। আমার প্রধান পদ্ধতিতে, আমার এই জাতীয় কোড রয়েছে:

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"/>

আমি লক্ষ্য করেছি যে প্যাকেজ.পাথের আর অস্তিত্ব নেই, তাই আমি কেবল ভাল করার জন্য লাইনটি ফেলেছি।

এবং তার পরে, এনপিই আসতে শুরু pep-config.xmlকরেছিল a একটিতে আমার কাছে মাত্র 2 মটরশুটি ছিল:

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

এবং স্যাম্যাব্যাক ক্লাসের হিসাবে সম্পত্তি হিসাবে ঘোষিত একটি সম্পত্তি রয়েছে

@Autowired private Settings settings;

কিছু অজানা কারণে, সেটিংগুলি init () এ নাল হয়, যখন <context:component-scan/>উপাদানটি একেবারেই উপস্থিত হয় না, তবে যখন এটি উপস্থিত থাকে এবং বেসপ্যাকেজ হিসাবে কিছু বিএস থাকে, সমস্ত কিছুই ঠিকঠাকভাবে কাজ করে। এই লাইনটি এখন এর মতো দেখাচ্ছে:

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

এবং এটি কাজ করে। কেউ হতে পারে ব্যাখ্যা সরবরাহ করতে পারে তবে আমার জন্য এখনই এটি যথেষ্ট)


5
এই উত্তরটি ব্যাখ্যা। কাজ করার জন্য <context:component-scan/>স্পষ্টতই <context:annotation-config/>প্রয়োজনীয় সক্ষম করে তোলে @Autowired
ফরভিনিউর

3

এটি নলপয়েন্টারএক্সসেপশন দেওয়ার অপরাধী MileageFeeCalculator calc = new MileageFeeCalculator();আমরা স্প্রিং ব্যবহার করছি - ম্যানুয়ালি অবজেক্ট তৈরি করার দরকার নেই। আইওসি ধারক দ্বারা অবজেক্ট তৈরির যত্ন নেওয়া হবে।


2

আপনি সার্ভিস ক্লাসে @ সার্ভিস টিকা ব্যবহার করে এবং অন্যান্য শিমের ক্লাসবি কনস্ট্রাক্টরের কাছে প্রয়োজনীয় শিমের ক্লাসএ পাস করে একটি প্যারামিটার হিসাবে পাস করতে এবং @ অটোভায়ার্ড সহ ক্লাস বি এর কনস্ট্রাক্টরকে টিকা দিতে পারেন issue নমুনা স্নিপেট এখানে:

@Service
public class ClassB {

    private ClassA classA;

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

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

এটি আমার পক্ষে কাজ করেছে, আপনি কীভাবে এটি সমস্যার সমাধান করছেন তা দয়া করে বিস্তারিত বলতে পারেন?
ক্রুয়েলিঙ্গাইন

1
@ ক্রুয়েলজেইন, দেখুন এটি কেবল ক্ষেত্রের ইনজেকশন ব্যবহার না করে (যেখানে আপনি স্পষ্টভাবে কোনও বস্তু সেট করছেন) এটি বেশিরভাগ ক্ষেত্রে বসন্তের কনফিগারেশন দ্বারা সম্পন্ন হয়) look সুতরাং আপনি যদি "নতুন" অপারেটরটি ব্যবহার করে ক্লাসবিতে কোনও অবজেক্ট তৈরি করছেন তবে এটি অন্য কোনও স্কোপ হয় তবে তা ক্লাসএর জন্য দৃশ্যমান বা স্বতঃবাহিত সেট হবে না। সুতরাং, ClassB.useClassAObjectHere () কে কল করার সময় NPE নিক্ষেপ করবে কারণ আপনি যদি কেবলমাত্র ক্ষেত্রের ইনজেকশন ঘোষনা করেন তবে ClassA অবজেক্টটি স্বয়ংক্রিয়ভাবে গৃহীত হয়নি। পড়ুন ক্রাইলিস একই ব্যাখ্যা করার চেষ্টা করছে। এবং এই কারণেই ক্ষেত্রের ইনজেকশনের চেয়ে কনস্ট্রাক্টর ইঞ্জেকশন দেওয়ার পরামর্শ দেওয়া হচ্ছে। এটা কি এখন বোঝা যায়?
অভিষেক

1

এখানে যা উল্লেখ করা হয়নি তা "কার্যকর করার আদেশ" অনুচ্ছেদে এই নিবন্ধে বর্ণিত হয়েছে ।

"শিখার পরে" যে আমাকে @ কম্পিউটার বা ডেরিভেটিভস @ সার্ভিস বা @ রিপোসিটোরির (আমি অনুমান আরও কিছু আছে) দিয়ে একটি ক্লাস টিকা দিতে হয়েছিল, তাদের অভ্যন্তরের অন্যান্য উপাদানগুলি স্বতঃশক্ত করার জন্য, এটি আমাকে আঘাত করেছিল যে এই অন্যান্য উপাদানগুলি এখনও কনস্ট্রাক্টরের অভ্যন্তরে শূন্য ছিল মূল উপাদান।

@ পোস্টকনস্ট্রাক্ট ব্যবহার করে এটি সমাধান করে:

@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

  • আপনার শ্রেণি স্প্রেং বিন নয়।

  • ক্ষেত্রটি একটি বিন নয়।


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;
    }
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.