Issue
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);
}
// getters & setters...
}
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();
}
}
The rest is the same as before.
Why is
@Component
not creating Beans?It is working the way I think it should when 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.
Solution
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());
}
}
- Here is the sample repo https://github.com/kavi-kanap/stackoverflow-63072236
Answered By - Kavithakaran Kanapathippillai
Answer Checked By - Timothy Miller (JavaFixing Admin)