英文:
SpringBoot: Autowired works in Configuration, but returns null in Controller
问题
我的问题: 我已经创建了一个模型管理器的单例 Bean。尝试在我的控制器中进行自动装配,但是结果是空指针。然而,在我的配置中,同样的 Bean 的自动装配运行得很好。
我应该在这一点上注意,这不是我在这个项目中创建的第一个单例 Bean;就我所知,我已经按照所有其他 Bean 的方式创建了它们;它们都能正确地进行自动装配。这就是我现在感到困惑的主要原因。
代码:
主应用程序位于“project”包下,因此所有其他包都是该包的子包。为了简洁起见,我选择省略了导入部分,但是所有必要的导入都已经完成。
配置
package project.config;
@Configuration
public class BootstrapConfig {
@Bean
@Scope("singleton")
public ThingManager thingManager() {
return new thingManager();
}
@Autowired
private ThingManager manager;
@PostConstruct
public void initialize() {
manager.setup(); // 这个运行良好。
}
}
管理器
package project.model;
public class ThingManager {
private HashMap<String, Thing> things;
public ThingManager() {
things = new HashMap<String, Thing>();
}
public void setup() {
// 进行设置
}
public Thing getThing(String input) {
return things.get(input);
}
}
控制器
package project.controller;
@RestController
@RequestMapping("/api/things")
public class ThingController {
@Autowired
ThingManager manager; // 这是 null
private Thing thing;
public ThingController() {
this.thing = manager.getThing("test"); // 这会抛出空指针异常。
}
@GetMapping("/")
public ResponseEntity<Thing> showThing() {
return ResponseEntity.ok(thing);
}
}
我尝试过的:
我尝试过将 ThingManager
标记为 @Component @Scope(value = "singleton")
而不是手动设置 Bean(因此我在配置中删除了 @Bean
代码块);结果是一样的;配置可以完美地进行自动装配,但控制器不行。
我已经看过这个主题上的众多帖子,在这里已经有很多人忘记将他们要自动装配的类标记为组件或类似的情况。也许我忽视了与我的问题相似的地方;很难说。
英文:
My Problem: I have created a Singleton Bean of my model Manager. Trying to Autowire it in my Controller, however, results in a nullpointer. In my configuration, however, the Autowiring of the same Bean works just fine.
I should note at this point that this is not the first singleton Bean I have made in this project; and as far as I can tell, I have made it in the same vein as all the others; which all Autowire correctly. That's the main reason why I'm stumped right now.
The Code:
The Main App is under the 'project' package, so all other packages are sub-packages of that one.
I opted to omit the imports for brevity, but everything is imported as it should be.
Config
package project.config
@Configuration
public class BootstrapConfig {
@Bean
@Scope("singleton")
public ThingManager thingManager() {
return new thingManager();
}
@Autowired
private ThingManager manager;
@PostConstruct
public void initialize() {
manager.setup() //This works fine.
}
}
Manager
package project.model
public class ThingManager {
private HashMap<String, Thing> things;
public ThingManager() {
things = new HashMap<String, Thing>();
}
public void setup() {
//Do setup Things
}
public Thing getThing(String input) {
return things.get(input);
}
}
Controller
package project.controller
@RestController
@RequestMapping("/api/things")
public class ThingController {
@Autowired
ThingManager manager; //This is null
private Thing thing;
public ThingController() {
this.thing = manager.getThing("test"); //This then throws NullPointer.
}
@GetMapping("/")
public ResponseEntity<Thing> showThing() {
return ResponseEntity.ok(thing);
}
}
What I have tried:
I have tried marking ThingManager as @Component @Scope(value = "singleton")
instead of setting up the Bean manually (so I removed the @Bean
code-block in the configuration); the result is the same; Configuration can Autowire it perfectly fine, but Controller cannot.
I have looked at the myriad of posts about this topic already on here, but most seem to be about someone having forgotten to mark the class they Autowire in as a component or similar. Maybe I overlooked a similarity to my problem; it's hard to tell.
答案1
得分: 3
Spring只能在对象被创建(调用构造函数)后才能自动装配字段,所以在ThingController的构造函数中访问manager
时,它尚未被注入。在构造函数中使用manager
的最简单方法是将其添加为构造函数参数,而不是自动装配(Spring将使用可用的bean作为参数):
// ...
public class ThingController {
private final Thing thing;
public ThingController(ThingManager manager) {
this.thing = manager.getThing("test");
}
// ...
}
英文:
Spring can autowire fields only after the object is created (the constructor is called), so you're accessing the manager
in the constructor of ThingControler while it's not yet injected. The easiest way to use manager
in the constructor would be to add it as a constructor parameter instead of autowiring (Spring will use available bean for the parameter):
// ...
public class ThingController {
private final Thing thing;
public ThingController(ThingManager manager) {
this.thing = manager.getThing("test");
}
// ...
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论