Поле, аннотированное @Autowired
, является null
, потому что Spring не знает о копии MileageFeeCalculator
, которую вы создали с помощью new
, и не знал, чтобы ее автоустанавливать.
Контейнер Spring Inversion of Control (IoC) имеет три основных логических компонента: реестр (называемый ApplicationContext
) компонентов (beans), доступных для использования приложением, система настройки, которая вводит объектов в них путем сопоставления зависимостей с компонентами в контексте и решателя зависимостей, которые могут смотреть на конфигурацию множества различных компонентов и определять, как создавать и настраивать их в необходимом порядке.
Контейнер IoC не является волшебным, и он не может знать о Java-объектах, если вы как-то не сообщаете об этом. Когда вы вызываете new
, JVM создает экземпляр нового объекта и передает его прямо вам - он никогда не проходит процесс настройки. Есть три способа, которыми вы можете настроить свои компоненты.
Я опубликовал весь этот код, используя Spring Boot для запуска, в проекте GitHub ; вы можете посмотреть полный рабочий проект для каждого подхода, чтобы увидеть все, что вам нужно, чтобы заставить его работать. Тег с параметром NullPointerException
: nonworking
Наиболее предпочтительным вариантом является позволить Spring autowire все ваши компоненты; это требует наименьшего количества кода и является наиболее удобным для обслуживания. Чтобы сделать работу по автоустановке, как вы хотели, также автоустанавливайте 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
, которые будут автообновлены, вы можете использовать аннотацию Spring @Configurable
вместе с AspectJ компиляцией во время компиляции для ввода ваших объектов , Этот подход вставляет код в конструктор вашего объекта, который предупреждает Spring о том, что он создается, так что Spring может настроить новый экземпляр. Это требует некоторой конфигурации в вашей сборке (например, компиляции с ajc
) и включения обработчиков конфигурации среды Spring (@EnableSpringConfigured
с синтаксисом JavaConfig). Этот подход используется системой активных записей Roo, чтобы позволить экземплярам new
ваших объектов получать необходимую информацию о сохранении.
@Service
@Configurable
public class MileageFeeCalculator {
@Autowired
private MileageRateService rateService;
public float mileageCharge(final int miles) {
return (miles * rateService.ratePerMile());
}
}
Тег, который работает с помощью @Configurable
на объекте службы: working-configurable
Этот подход подходит только для взаимодействия с устаревшим кодом в особых ситуациях. Почти всегда предпочтительнее создавать одноэлементный класс адаптеров, который Spring может использовать для autowire, и устаревший код может вызывать, но можно напрямую спросить контекст приложения Spring для bean-компонента.
Для этого вам нужно класс, к которому 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