Поле, аннотированное @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
Попробуйте изменить следующее в tomcat-embed-jasper
Remove <scope>provided</scope> OR change the scope to compile <scope>compile</scope>
Ограничение JSP
При запуске приложения Spring Boot, использующего встроенный контейнер сервлета ( и упакован как исполняемый архив), есть некоторые ограничения в поддержке JSP.
Область действия
compile
Это область по умолчанию, используемая, если ни одна не указана. Зависимости компиляции доступны во всех classpath проекта. Кроме того, эти зависимости распространяются на зависимые проекты.
provided
Это очень похоже на компиляцию, но указывает, что вы ожидаете, что JDK или контейнер предоставят зависимость во время выполнения. Например, при создании веб-приложения для Java Enterprise Edition вы должны установить зависимость от API-интерфейса сервлета и связанных API-интерфейсов Java EE, так как веб-контейнер предоставляет эти классы. Эта область доступна только для пути к классам компиляции и тестирования и не является транзитивной.
runtime
Эта область указывает, что зависимость не требуется для компиляции, но предназначена для выполнения. Он находится во время выполнения и пути к классам теста, но не в пути к классам компиляции.