Поле зазначено @Autowiredв nullтому, що Spring не знає про копію, MileageFeeCalculatorяку ви створили, newі не знав, щоб її автоматично провести.
Контейнер Spring Inversion of Control (IoC) містить три основні логічні компоненти: реєстр (званий ApplicationContext) компонентів (бобів), які доступні для використання додатком; залежності від бобів у контексті та вирішення залежності, яке може переглянути конфігурацію багатьох різних бобів та визначити, як інстанціювати та конфігурувати їх у необхідному порядку.
Контейнер IoC не є магічним, і він не може знати про об'єкти Java, якщо ви якось не інформуєте про них. Коли ви телефонуєте new, JVM створює копію нового об'єкта і передає його вам прямо - він ніколи не проходить процес конфігурації. Існує три способи налаштування бобів.
Я опублікував весь цей код, використовуючи Spring Boot для запуску, на цьому проекті GitHub ; ви можете переглянути повноцінний проект для кожного підходу, щоб побачити все необхідне для його роботи. Позначити тегом NullPointerException:nonworking
Введіть свою квасолю
Найбільш кращий варіант - дозволити Spring вести автопровід усіх ваших бобів; для цього потрібна найменша кількість коду і є найбільш рентабельною. Щоб автопроводка працювала так, як ви хотіли, також автопровід MileageFeeCalculatorтак:
@Controller
public class MileageFeeController {
@Autowired
private MileageFeeCalculator calc;
@RequestMapping("/mileage/{miles}")
@ResponseBody
public float mileageFee(@PathVariable int miles) {
return calc.mileageCharge(miles);
}
}
Якщо вам потрібно створити новий примірник вашого сервісного об’єкта для різних запитів, ви все одно можете використовувати ін'єкцію за допомогою діапазонів Spring Bean .
Тег, який працює шляхом введення @MileageFeeCalculatorоб’єкта обслуговування:working-inject-bean
Використовуйте @Configurable
Якщо вам справді потрібні об'єкти, створені за допомогою newавтоматичного з'єднання, ви можете використати весняну @Configurableпримітку разом із сплетінням часу компіляції AspectJ для введення об’єктів. Цей підхід вставляє код у конструктор вашого об'єкта, який попереджає Spring про те, що він створюється, щоб Spring міг налаштувати новий екземпляр. Для цього потрібна невелика конфігурація у вашій збірці (наприклад, компіляція ajc) та ввімкнення оброблювачів конфігурації Spring для виконання ( @EnableSpringConfiguredіз синтаксисом JavaConfig). Цей підхід використовується системою Roo Active Record, щоб дозволити newінстанціям ваших організацій отримати необхідну постійну інформацію.
@Service
@Configurable
public class MileageFeeCalculator {
@Autowired
private MileageRateService rateService;
public float mileageCharge(final int miles) {
return (miles * rateService.ratePerMile());
}
}
Тег, який працює за допомогою @Configurableоб’єкта служби:working-configurable
Ручний пошук квасолі: не рекомендується
Цей підхід підходить лише для взаємодії зі застарілим кодом у особливих ситуаціях. Практично завжди бажано створити однотонний клас адаптерів, який Spring може автопроводити і застарілий код може викликати, але можна прямо запитати контекст програми Spring для бобів.
Для цього вам потрібен клас, на який 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
Fвикликається всередині конструктора іншогоS. У цьому випадку передайте необхідний квасоляFяк параметр іншомуSконструктору бобів та анотуйте конструкторSз@Autowire. Пам'ятайте , анотувати клас першого бобуFз@Component.