Аннотированное поле @Autowired
объясняется null
тем, что Spring не знает о копии, MileageFeeCalculator
которую вы создали, new
и не знал, как автоматически связать ее.
Контейнер Spring Inversion of Control (IoC) имеет три основных логических компонента: реестр (так называемый ApplicationContext
) компонентов (компонентов), доступных для использования приложением, система конфигуратора, которая внедряет в них зависимости объектов путем сопоставления зависимости с bean-компонентами в контексте и средство решения зависимостей, которое может просматривать конфигурацию множества различных bean-компонентов и определять, как создавать экземпляры и настраивать их в необходимом порядке.
Контейнер IoC не волшебен, и у него нет возможности узнать об объектах Java, если вы как-то не сообщите ему о них. Когда вы вызываете new
, JVM создает копию нового объекта и передает ее вам - она никогда не проходит через процесс настройки. Есть три способа настроить ваши bean-компоненты.
Я разместил весь этот код, используя 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);
}
}
Если вам нужно создать новый экземпляр объекта службы для разных запросов, вы все равно можете использовать инъекцию с помощью областей действия bean-компонента Spring .
Тег, который работает путем внедрения @MileageFeeCalculator
объекта службы:working-inject-bean
Используйте @Configurable
Если вам действительно нужны объекты, созданные с помощью new
автоматического подключения, вы можете использовать @Configurable
аннотацию Spring вместе с переплетением во время компиляции 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);
}
}
Тег, который работает путем ручного поиска объекта службы в контексте Spring: working-manual-lookup
F
вызывается внутри конструктора другого компонентаS
. В этом случае передайте необходимый bean-компонентF
в качестве параметра другомуS
конструктору bean-компонентов и аннотируйте конструкторS
with@Autowire
. Не забудьте аннотировать класс первого компонентаF
с@Component
.