[英]Error creating bean while using Autowired
I have a simple Springboot application in which I am trying to use in memory HashMap as a DB to store some info.我有一个简单的 Springboot 应用程序,我试图在其中使用 memory HashMap 作为数据库来存储一些信息。 This is my restcontroler
这是我的休息控制器
@RestController
public class Parking {
@Autowired
ParkingServices parkingServices;
@Autowired
Vehicle vehicle;
@GetMapping("/test")
public void park() {
vehicle = Vehicle.builder().color("Blue").plateNumber("qwew").build();
parkingServices.parkCar(vehicle);
}
@GetMapping("/")
public void Test() {
System.out.println("test");
}
}
This is my simple parking service这是我的简单停车服务
@Service
public class ParkingServices {
@Autowired
ParkingLotService parkingLot;
public ParkingServices() {
parkingLot.init(10);
}
public int parkCar(Vehicle vehicle) {
return parkingLot.parkCar(vehicle);
}
}
And this is my ParkingLot service这是我的停车场服务
@Service
public class ParkingLotService {
private int size = 0;
private HashMap<Integer, Slot> parkingSlots = new HashMap<>();
private Stack<Integer> st = new Stack<>();
public void init(int size) {
this.size = size;
parkingSlots = new HashMap<>();
for (int i = 0; i < size; i++) {
parkingSlots.put(i, new ParkingSlot());
st.push(i);
}
}
public int parkCar(Vehicle vehicle) {
int firstPark = st.pop();
Slot slot = parkingSlots.get(firstPark);
slot.parkVehicle(vehicle);
parkingSlots.put(firstPark, slot);
return firstPark;
}
public void removeCar(int parkingNumber) {
Slot slot = parkingSlots.get(parkingNumber);
}
}
Now when i try to run the application I am getting this error as a stack trace现在,当我尝试运行应用程序时,我收到此错误作为堆栈跟踪
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'parking': Unsatisfied dependency expressed through field 'parkingServices'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'parkingServices' defined in file [D:\Projects\parking\demo\target\classes\com\parking\demo\Services\ParkingServices.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.parking.demo.Services.ParkingServices]: Constructor threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:660) ~[spring-beans-5.3.5.jar:5.3.5]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640) ~[spring-beans-5.3.5.jar:5.3.5]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119) ~[spring-beans-5.3.5.jar:5.3.5]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399) ~[spring-beans-5.3.5.jar:5.3.5]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1413) ~[spring-beans-5.3.5.jar:5.3.5]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) ~[spring-beans-5.3.5.jar:5.3.5]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524) ~[spring-beans-5.3.5.jar:5.3.5]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.5.jar:5.3.5]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.5.jar:5.3.5]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.5.jar:5.3.5]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.5.jar:5.3.5]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944) ~[spring-beans-5.3.5.jar:5.3.5]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-5.3.5.jar:5.3.5]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.5.jar:5.3.5]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:144) ~[spring-boot-2.4.4.jar:2.4.4]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:769) [spring-boot-2.4.4.jar:2.4.4]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:761) [spring-boot-2.4.4.jar:2.4.4]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:426) [spring-boot-2.4.4.jar:2.4.4]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:326) [spring-boot-2.4.4.jar:2.4.4]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1313) [spring-boot-2.4.4.jar:2.4.4]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302) [spring-boot-2.4.4.jar:2.4.4]
at com.parking.demo.ParkingApplication.main(ParkingApplication.java:11) [classes/:na]
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'parkingServices' defined in file [D:\Projects\parking\demo\target\classes\com\parking\demo\Services\ParkingServices.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.parking.demo.Services.ParkingServices]: Constructor threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1316) ~[spring-beans-5.3.5.jar:5.3.5]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1214) ~[spring-beans-5.3.5.jar:5.3.5]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564) ~[spring-beans-5.3.5.jar:5.3.5]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524) ~[spring-beans-5.3.5.jar:5.3.5]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.5.jar:5.3.5]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.5.jar:5.3.5]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.5.jar:5.3.5]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.5.jar:5.3.5]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.3.5.jar:5.3.5]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1380) ~[spring-beans-5.3.5.jar:5.3.5]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1300) ~[spring-beans-5.3.5.jar:5.3.5]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:657) ~[spring-beans-5.3.5.jar:5.3.5]
... 21 common frames omitted
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.parking.demo.Services.ParkingServices]: Constructor threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:225) ~[spring-beans-5.3.5.jar:5.3.5]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:87) ~[spring-beans-5.3.5.jar:5.3.5]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1308) ~[spring-beans-5.3.5.jar:5.3.5]
... 32 common frames omitted
Caused by: java.lang.NullPointerException: null
at com.parking.demo.Services.ParkingServices.<init>(ParkingServices.java:15) ~[classes/:na]
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_252]
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_252]
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_252]
at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[na:1.8.0_252]
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:212) ~[spring-beans-5.3.5.jar:5.3.5]
... 34 common frames omitted
I know its due to Autowired is not working on ParkingLotService, its ability to work if instead of Autowired in ParkingService, I directly try to initialize Object but not the other way around.我知道它是由于 Autowired 不能在 ParkingLotService 上工作,如果不是在 ParkingService 中 Autowired,它的工作能力,我直接尝试初始化 Object 但不是相反。 Can someone help me with it?
有人可以帮我吗? Why Autowired is not working and how to make it work.
为什么 Autowired 不起作用以及如何使其起作用。
Spring @Autowired
field injection after construction invoked. Spring
@Autowired
构造调用后的字段注入。
See:看:
Autowired Fields
Fields are injected right after construction of a bean, before any config methods are invoked. Such a config field does not have to be public.
So for your scenario, you can use:因此,对于您的场景,您可以使用:
ParkingLotService
and invoke the init
method.ParkingLotService
并调用init
方法。 @Autowired
public ParkingServices(ParkingLotService parkingLot) {
parkingLot.init(10);
this.parkingLot = parkingLot;
}
@PostConstruct
method to invoke the init
method@PostConstruct
方法调用init
方法@PostConstruct
public void myInit() {
parkingLot.init(10);
}
TL;DR: Use Constructor-based DI TL;DR:使用基于构造函数的 DI
@Autowired
atop constructor@Autowired
移到构造函数的顶部You got this UnsatisfiedDependencyException
because:你得到这个
UnsatisfiedDependencyException
因为:
Error creating bean with name 'parking':
创建名称为“parking”的 bean 时出错:
This bean could not be created because:无法创建此bean ,因为:
Unsatisfied dependency expressed through field 'parkingServices';
通过字段“parkingServices”表示的不满足的依赖关系;
So the field could not be autowired by Spring with a dependency because of a NullPointerException (NPE) :因此,由于NullPointerException (NPE) ,Spring无法自动装配该字段,并具有依赖关系:
nested exception is org.springframework.beans.factory.BeanCreationException: Constructor threw exception;
嵌套异常是 org.springframework.beans.factory.BeanCreationException:构造函数抛出异常; nested exception is java.lang.NullPointerException
嵌套异常是 java.lang.NullPointerException
Continue to answer explaining M. Deinum comment below :继续回答以下解释 M. Deinum 评论:
The problem is the accessing of a variable before it is available.
问题是在变量可用之前对其进行访问。
The NPE was raised when the constructor of ParkingServices
tries to call init
on the field parkingLot
, because the field was null
.当
ParkingServices
的构造函数尝试在字段parkingLot
上调用init
时引发 NPE,因为该字段是null
。
@Autowired
ParkingLotService parkingLot; // field autowired in 2nd step
public ParkingServices() {
parkingLot.init(10); // constructor called in 1st step, hence NPE
}
@Autowired
Explained @Autowired
解释Spring's @Autowired
is a Java-annotation to facilitate Dependency-Injection (DI). Spring 的
@Autowired
是一种 Java 注释,用于促进依赖注入 (DI)。
Spring as most DI-frameworks offers 3 different ways of DI: Spring 因为大多数 DI 框架提供 3 种不同的 DI 方式:
In your case you use Field-based DI.在您的情况下,您使用基于字段的 DI。 This fails, because Spring first calls the constructor before autowiring fields (= injecting beans into Autowired annotated fields).
这失败了,因为 Spring在自动装配字段之前首先调用构造函数(= 将 bean 注入 Autowired 注释字段)。
See the tutorial of LogicBig (2020): Spring - Different ways of injecting dependencies It shows a nice illustration:请参阅LogicBig (2020) 的教程: Spring - 注入依赖项的不同方式它展示了一个很好的插图:
Your constructor fails with a NPE, because it calls a method on a null
field.您的构造函数因 NPE 而失败,因为它调用了
null
字段上的方法。 The field is null
because it was not yet instantiated, ie autowired .该字段是
null
因为它尚未实例化,即autowired 。 And it will not unless the constructor succeeds.除非构造函数成功,否则它不会。
Use Constructor-based DI by adding the field as parameter to the constructor and moving the @Autowired
annotation form field to constructor.通过将字段作为参数添加到构造函数并将
@Autowired
注释表单字段移动到构造函数来使用基于构造函数的DI。
ParkingLotService parkingLot; // field autowired by constructor in 1nd step
@Autowired // tells Spring to inject suitable beans for parameters
public ParkingServices(ParkingLotService parkingLot) { // add field as required dependency
this.parkingLot = parkingLot; // instantiate field
this.parkingLot.init(10); // call init on non-null field, avoid NPE
}
This way you can instantiate and call init
methods on the field in the same code block.这样,您可以在同一代码块中的字段上实例化和调用
init
方法。 So related code is near in scope, near to understand, near to maintain.所以相关代码在scope附近,近看懂,近维护。
See the comparison of DI-methods and their benefis in Rizvi's Blog: Different Types of Bean Injection in Spring :请参阅Rizvi博客中的 DI 方法及其好处的比较:Spring 中的不同类型的 Bean 注入:
As M. Deinum commented on your question:正如M. Deinum对您的问题的评论:
Calling
init
is btw a bad idea, because if you use this in multiple classes this will lead to issues .顺便说一句,调用
init
是个坏主意,因为如果您在多个类中使用它,这将导致问题。 The service is a singleton shared between those classes...该服务是在这些类之间共享的singleton ...
(bold emphasis by me) (我粗体强调)
This side-effect could be solved by "initializing" the ParkingLotService
right away in its constructor, like:这种副作用可以通过立即在其构造函数中“初始化”
ParkingLotService
来解决,例如:
public ParkingLotService(int size) { // former init
this.size = size;
this.parkingSlots = new HashMap<>();
for (int i = 0; i < size; i++) {
this.parkingSlots.put(i, new ParkingSlot());
this.freeParkStack.push(i); // renamed `st` to `freeParkStack`
}
}
This way your singleton is "initialized" once, guaranteed and mandatory (because done with constructor, nobody will forget to init it).通过这种方式,您的singleton被“初始化”一次,保证和强制(因为使用构造函数完成,没有人会忘记初始化它)。 If a re-initialisation (here resizing) is still needed, the code can be extracted into a separate method later.
如果仍需要重新初始化(此处调整大小),则可以稍后将代码提取到单独的方法中。
General advices:一般建议:
this.
this.
to distinguish them from parameters (also avoids compiler errors when same names assigned) Get further review, tips and improvements!获得进一步的评论、提示和改进! Post your working code on the sister-site: http://codereview.stackexchange.com
在姐妹网站上发布您的工作代码: http://codereview.stackexchange.com
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.