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;
}
}
为什么 @Component
没有创建 Bean?
它的工作方式与我认为它应该在网络应用程序的 @Controller
中使用的方式一样,这有什么不同吗? @Bean
和 @Component
究竟有何不同?
我哪里没看懂?
编辑
考虑以下场景:
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 的正确方法。
因为根据文档 @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;
}
}
为什么
@Component
没有创建 Bean?它的工作方式与我认为它应该在网络应用程序的
@Controller
中使用的方式一样,这有什么不同吗?@Bean
和@Component
究竟有何不同?我哪里没看懂?
编辑
考虑以下场景:
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 的正确方法。