Spring 启动 @Component 不创建 Bean

Spring Boot @Component doesn't create Beans

因为根据文档 @Component 为 Spring 容器注册了 bean,所以我尝试使用以下代码创建一个简单的依赖注入示例:

package pl.playground;

//...

@SpringBootApplication
public class PlaygroundApplication {

    @Autowired
    private static Building building;

    public static void main(String[] args) {
        building.setBuildingSize(12L);
        System.out.println(building.monthlyHeatingCost());
    }
}
package pl.playground.facade;

//...

@Component
public class Building {

    private HeatingService service;
    private Long buildingSize;

    @Autowired
    public Building(HeatingService service) {
        this.service = service;
    }

    public Double monthlyHeatingCost() {
        return service.getMonthlyHeatingCost(buildingSize);
    }

    public void setBuildingSize(Long buildingSize) {
        this.buildingSize = buildingSize;
    }
}
package pl.playground.service;

public interface HeatingService {

    Double getMonthlyHeatingCost(Long size);
}
package pl.playground.service;

//...

@Component
public class HeatingServiceImpl implements HeatingService {

    private final Double CUBIC_PRICE = 2.3;

    public HeatingServiceImpl() {}

    @Override
    public Double getMonthlyHeatingCost(Long size) {
        return size * CUBIC_PRICE;
    }   
}

它构建并运行,但在 building.setBuildingSize(12L); 处有一个 NullPointerException。然而,下面的一个没有任何问题:

//PlaygroundApplication.java
package pl.playground;

//...

@SpringBootApplication
public class PlaygroundApplication {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);

        Building building = context.getBean(Building.class);

        building.setBuildingSize(12L);
        System.out.println(building.monthlyHeatingCost());
    }
}
package pl.playground.config;

//...

@Configuration
public class Config {

    @Bean
    public Building building(HeatingService service) {
        return new Building(service);
    }

    @Bean
    public HeatingServiceImpl heatingServiceImpl() {
        return new HeatingServiceImpl();
    }
}
package pl.playground.facade;

//...

public class Building {

    private HeatingService service;
    private Long buildingSize;

    public Building(HeatingService service) {
        this.service = service;
    }

    public Double monthlyHeatingCost() {
        return service.getMonthlyHeatingCost(buildingSize);
    }
    
    public Long getBuildingSize() {
        return buildingSize;
    }

    public void setBuildingSize(Long buildingSize) {
        this.buildingSize = buildingSize;
    }
}
package pl.playground.service;

public interface HeatingService {

    Double getMonthlyHeatingCost(Long size);
}
package pl.playground.service;

public class HeatingServiceImpl implements HeatingService {

    private final Double CUBIC_PRICE = 2.3;

    public HeatingServiceImpl() {}

    @Override
    public Double getMonthlyHeatingCost(Long size) {
        return size * CUBIC_PRICE;
    }   
}

编辑

考虑以下场景:

package pl.playground;

//...

@SpringBootApplication
public class ExampleApplication {

    public static void main(String[] args) {
        SpringApplication.run(ExampleApplication.class, args);
    }
}
package pl.playground.controller;

//...

@Controller
public class Controller {

    private Facade facade;

    @Autowired
    public Controller(Facade facade) {
        this.facade = facade;
    }

    @GetMapping("/")
    public String getIndexPage(Model model) {
        return "index";
    }
}
package pl.playground.facade;

//...

@Component
public class Facade {

    private PostsService postService;
    private UserService userService;
    private TagService tagService;

    @Autowired
    public Facade(PostsService retrieve, UserService user, TagService tag) {
        this.postService = retrieve;
        this.userService = user;
        this.tagService = tag;
    }

    //...
}

我不需要 @Configuration 在这里它就可以工作。这是我关心的问题。

嗯。我使用了您的原始问题并且没有任何问题。 @cezary-butler 在评论中指出你可以 autowire 进入 PlaygroundApplication 但你可以在静态 main 方法中使用 context.getBean(Building.class)

轻松掌握它
    @SpringBootApplication
    public class PlaygroundApplication {

      public static void main(String[] args) {
        ConfigurableApplicationContext context = 
              SpringApplication.run(PlaygroundApplication.class);
        Building building = context.getBean(Building.class);
        building.setBuildingSize(12L);
        System.out.println(building.monthlyHeatingCost());
      }
    }

您的代码存在问题,您正试图 @Autowire 在静态字段上。你根本不能那样做。看这里:Can you use @Autowired with static fields?

它无法工作,因为 PlaygroundApplication class 不是由 spring 创建和管理的。注入仅在 spring 管理的实例内部有效。您可以将使用 @SpringBootApplication 注释的 class 视为配置 classes。 Spring 创建那些 classes 的实例并在其中注入,但仅在实例字段上工作。

第二个示例显示了从应用程序的 main 方法访问 spring bean 的正确方法。