Поле зазначено @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
.