简体   繁体   English

使用 Autowired 创建 bean 时出错

[英]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.

Spring Autowired Spring 自动接线

So for your scenario, you can use:因此,对于您的场景,您可以使用:

  1. Autowired Constructors to inject ParkingLotService and invoke the init method.自动装配的构造函数注入ParkingLotService并调用init方法。
    @Autowired
    public ParkingServices(ParkingLotService parkingLot) {
        parkingLot.init(10);
        this.parkingLot = parkingLot;
    }
  1. use @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

  1. move the @Autowired atop constructor@Autowired移到构造函数的顶部
  2. add field as parameter to constructor and assign therein first将字段作为参数添加到构造函数并首先在其中分配

Error Analysed错误分析

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
}

Spring's @Autowired Explained Spring 的@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 方式:

  1. Constructor-based DI基于构造函数的 DI
  2. Field-based DI基于现场的 DI
  3. Setter-based DI基于设置器的 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 - 注入依赖项的不同方式它展示了一个很好的插图: 不同的 DI 形式

Vicious circle of dependencies依赖的恶性循环

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.除非构造函数成功,否则它不会。

Solution recommended推荐解决方案

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
}

Benefits好处

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 注入

场- VS 构造函数-注入

Bonus Review奖金审查

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:一般建议:

  • always name your variables to express purpose (avoid abbreviations)总是命名你的变量来表达目的(避免缩写)
  • prefix a classes fields with 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.

相关问题 使用@Autowired时,使用名称创建bean时出错 - Error creating bean with name while using @Autowired 使用@Required和@Autowired时创建bean时出错 - Error in creation of bean while using @Required and @Autowired @Autowired创建名称为bean的错误 - @Autowired Error creating bean with name 创建bean时出错:自动连接依赖项注入失败; - Error creating bean: Injection of autowired dependencies failed; 创建bean的错误:自动连接依赖项的注入失败 - Error of creating bean :injectionof autowired dependencies failed 创建名称为“ homeController”的bean时出错:自动连接的依赖项注入失败 - Error creating bean with name 'homeController': Injection of autowired dependencies failed 创建名为“countriesDao”的 bean 时出错:注入自动装配的依赖项失败; - Error creating bean with name 'countriesDao': Injection of autowired dependencies failed; 创建名称为&#39;serviceController&#39;的bean时出错:自动连接的依赖项注入失败; - Error creating bean with name 'serviceController': Injection of autowired dependencies failed; 使用 controller 创建 bean 时出错。 面临自动装配和限定符注释的问题 - Error creating bean with controller. Facing issues with autowired and qualifier annotations BeanCreationException:创建名称为&#39;userController&#39;的bean时出错:自动连接依赖项的注入失败 - BeanCreationException: Error creating bean with name 'userController': Injection of autowired dependencies failed
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM