Stack Overflow Asked by bart-kosmala on December 27, 2021
Since according to the docs @Component
registers beans for the Spring container I’m trying to create a simple example of dependency injection using the following code:
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;
}
}
It builds and runs, but there is a NullPointerException
at building.setBuildingSize(12L);
. However the one below works without any issues:
//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;
}
}
Why is @Component
not creating Beans?
It is working the way I think it should used inside a @Controller
of a web app, does that make a difference? How does exactly @Bean
and @Component
differ?
What am I failing to understand?
EDIT
Consider the following scenario:
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;
}
//...
}
I don’t need @Configuration
here for it to work. That’s my concern.
The problem with your code is that you are trying to @Autowire
on a static field. You simply cannot do that. Look here: Can you use @Autowired with static fields?
It fails to work because the PlaygroundApplication
class is not being created and managed by spring. The injection works only inside instances managed by spring. You can treat class annotated with @SpringBootApplication
as configuration classes. Spring creates instances of those classes and injection works inside them but only on instance fields.
The second example shows the correct way to access spring beans from main
method of the application.
Answered by Cezary Butler on December 27, 2021
Well. I used your original question and is working without any issues. @cezary-butler pointed out in the comments you can autowire
into PlaygroundApplication
but you can get hold of it easily in the static main method using 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());
}
}
Answered by Kavithakaran Kanapathippillai on December 27, 2021
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP