12 ответов:
поле с аннотацией
@Autowiredиnullпотому что весна не знает о копияMileageFeeCalculatorСnewи не знал, чтобы autowire его.инверсия пружины контейнера управления (IoC) имеет три основных логических компонента: реестр (называемый
ApplicationContext) компонентов (бобов), которые доступны для использования приложением, система конфигуратора, которая вводит зависимости объектов в них путем сопоставления зависимостей с компоненты в контексте и решатель зависимостей, который может просматривать конфигурацию многих различных компонентов и определять, как создавать и настраивать их в нужном порядке.контейнер IoC не волшебный, и он не имеет никакого способа узнать об объектах Java, если вы каким-то образом не сообщите ему о них. Когда вы звоните
new, JVM создает экземпляр нового объекта и передает его прямо вам-он никогда не проходит через процесс настройки. Есть три способа, которыми вы можете получите ваши бобы настроены.я написал весь этот код, используя Spring Boot для запуска, в этот проект GitHub; вы можете посмотреть на полный запуск проекта для каждого подхода, чтобы увидеть все, что вам нужно, чтобы заставить его работать. тега
NullPointerException:nonworkingввести свой зерен
наиболее предпочтительным вариантом является позволить Spring autowire все ваши бобы; это требует наименьшего количества кода и является самый ремонтопригодный. Чтобы автопроводка работала так, как вы хотели, также autowire
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 scopes.
тег, который работает путем инъекций
@MileageFeeCalculatorсервис объекта:working-inject-beanИспользовать @Настраиваемые!--42-->
Если вам действительно нужно объекты, созданные с помощью
newчтобы быть autowired, вы можете использовать весной@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 может автоматически подключаться и вызывать устаревший код,но можно напрямую запросить контекст приложения Spring для компонента.
для этого вам нужен класс, к которому Spring может дать ссылку на
Если вы не кодируете веб-приложение, убедитесь, что ваш класс, в котором выполняется @Autowiring, является Spring bean. Как правило, spring container не будет знать о классе, который мы можем рассматривать как spring bean. Мы должны рассказать весеннему контейнеру о наших весенних классах.
Это может быть достигнуто путем настройки в appln-contxt или лучше это аннотировать класс как @Component и, пожалуйста, не создавайте аннотированный класс с помощью new оператор. Убедитесь, что вы получаете его из Appln-контекста, как показано ниже.
@Component public class MyDemo { @Autowired private MyService myService; /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub System.out.println("test"); ApplicationContext ctx=new ClassPathXmlApplicationContext("spring.xml"); System.out.println("ctx>>"+ctx); Customer c1=null; MyDemo myDemo=ctx.getBean(MyDemo.class); System.out.println(myDemo); myDemo.callService(ctx); } public void callService(ApplicationContext ctx) { // TODO Auto-generated method stub System.out.println("---callService---"); System.out.println(myService); myService.callMydao(); } }
На самом деле, вы должны использовать либо управляемые объекты JVM, либо управляемый объект Spring для вызова методов. из вашего кода выше в вашем классе контроллера вы создаете новый объект для вызова вашего класса обслуживания, который имеет автоматически подключенный объект.
MileageFeeCalculator calc = new MileageFeeCalculator();Так что это не будет работать таким образом.
решение делает этот MileageFeeCalculator как авто-проводной объект в самом контроллере.
изменить ваш класс контроллера, как показано ниже.
@Controller public class MileageFeeController { @Autowired MileageFeeCalculator calc; @RequestMapping("/mileage/{miles}") @ResponseBody public float mileageFee(@PathVariable int miles) { return calc.mileageCharge(miles); } }
Я однажды столкнулся с той же проблемой, когда я не совсем привык к
the life in the IoC world. Элемент@Autowiredполе одного из моих бобов имеет значение null во время выполнения.основная причина заключается в том, что вместо использования автоматически созданного компонента, поддерживаемого контейнером Spring IoC (чей
ваша проблема является новой (создание объекта в стиле java)
MileageFeeCalculator calc = new MileageFeeCalculator();аннотации
@Service,@Component,@Configurationбобы создаются в
контекст приложения Spring при запуске сервера. Но когда мы создаем объекты с помощью оператора new объект не регистрируется в уже созданном контексте приложения. Например Сотрудник.java класс, который я использовал.зацени вот это:
public class ConfiguredTenantScopedBeanProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { String name = "tenant"; System.out.println("Bean factory post processor is initialized"); beanFactory.registerScope("employee", new Employee()); Assert.state(beanFactory instanceof BeanDefinitionRegistry, "BeanFactory was not a BeanDefinitionRegistry, so CustomScope cannot be used."); BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; for (String beanName : beanFactory.getBeanDefinitionNames()) { BeanDefinition definition = beanFactory.getBeanDefinition(beanName); if (name.equals(definition.getScope())) { BeanDefinitionHolder proxyHolder = ScopedProxyUtils.createScopedProxy(new BeanDefinitionHolder(definition, beanName), registry, true); registry.registerBeanDefinition(beanName, proxyHolder.getBeanDefinition()); } } } }
это, кажется, редкий случай, но вот что случилось со мной:
мы
@Injectвместо@Autowiredкоторый является стандартом javaee, поддерживаемым весной. В каждом месте он работал нормально, и бобы вводились правильно, а не в одном месте. Инъекции зернах, как представляется, то же@Inject Calculator myCalculatorнаконец мы обнаружили, что ошибка заключалась в том, что мы (на самом деле, функция автоматического завершения Eclipse) импортировали
com.opensymphony.xwork2.Injectвместоjavax.inject.Inject!Итак, убедитесь, что ваш аннотации (
@Autowired,@Inject,@Service,... ) есть правильные пакеты!
Я новичок в Spring, но я обнаружил это рабочее решение. Пожалуйста, скажите мне, если это недопустимый способ.
Я делаю весной впрыснуть
applicationContextв этой фасоли:import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; @Component public class SpringUtils { public static ApplicationContext ctx; /** * Make Spring inject the application context * and save it on a static variable, * so that it can be accessed from any point in the application. */ @Autowired private void setApplicationContext(ApplicationContext applicationContext) { ctx = applicationContext; } }вы можете поместить этот код в главный класс приложения, если вы хотите.
другие классы могут использовать его следующим образом:
MyBean myBean = (MyBean)SpringUtils.ctx.getBean(MyBean.class);таким образом любой Боб может быть получен любым объектом в приложении (также intantiated с
new) и в статическом виде.
Я думаю, что вы пропустили, чтобы поручить spring сканировать классы с аннотацией.
можно использовать
@ComponentScan("packageToScan")в классе конфигурации вашего приложения spring для указания spring для сканирования.
@Service, @Componentetc аннотации добавить мета-описание.Spring только вводит экземпляры тех классов, которые либо созданы как бобы, либо отмечены аннотацией.
классы, отмеченные аннотацией, должны быть идентифицированы весной до инъекции,
@ComponentScanпроинструктируйте spring искать классы, отмеченные аннотацией. Когда весна находит@Autowiredон ищет связанный компонент и вводит требуемый экземпляр.добавление аннотации только, не исправить или облегчить инъекцию зависимости, весна должна знать, где искать.
другое решение было бы положить вызов:
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)
Чтобы конструктор MileageFeeCalculator выглядел так:@Service public class MileageFeeCalculator { @Autowired private MileageRateService rateService; // <--- will be autowired when constructor is called public MileageFeeCalculator() { SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this) } public float mileageCharge(final int miles) { return (miles * rateService.ratePerMile()); } }
вы также можете исправить эту проблему, используя аннотацию @Service для класса обслуживания и передавая требуемый класс bean в качестве параметра конструктору других классов beans classB и аннотировать конструктор classB с помощью @Autowired. Пример фрагмента здесь:
@Service public class ClassB { private ClassA classA; @Autowired public ClassB(ClassA classA) { this.classA = classA; } public void useClassAObjectHere(){ classA.callMethodOnObjectA(); } }
обновление: действительно умные люди быстро указывали на этой ответ, который объясняет странность, описанную ниже
ОРИГИНАЛЬНЫЙ ОТВЕТ:
Я не знаю, помогает ли это кому-нибудь, но я застрял с той же проблемой, даже когда делал все, казалось бы, правильно. В моем основном методе у меня есть такой код:
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "common.xml", "token.xml", "pep-config.xml" }); TokenInitializer ti = context.getBean(TokenInitializer.class);и
token.xmlфайл у меня была строка<context:component-scan base-package="package.path"/>я заметил, что пакет.путь больше не существует, поэтому я просто отбросил линию навсегда.
и после этого, NPE начал приходить. В
pep-config.xmlу меня было всего 2 бобы:<bean id="someAbac" class="com.pep.SomeAbac" init-method="init"/> <bean id="settings" class="com.pep.Settings"/>и класс SomeAbac имеет свойство, объявленное как
@Autowired private Settings settings;по какой-то неизвестной причине, настройки null in init (), когда
<context:component-scan/>элемент отсутствует вообще, но когда он присутствует и имеет некоторые bs в качестве базового пакета, все работает хорошо. Эта строка теперь выглядит так:<context:component-scan base-package="some.shit"/>и это работает. Может быть кто-то может дать объяснение, но для меня этого достаточно сейчас )
Если это происходит в тестовом классе, убедитесь, что вы не забыли аннотировать класс.
например,Spring Boot:
@RunWith(SpringRunner.class) @SpringBootTest public class MyTests { ....
Comments