I am totally confused about mixing of "wiring in JavaConfig" and "wiring using @Autowired". I will tell you my problems in 4 scenarios:
(I am ok with mixing of @Autowired and stereotype annotations and I don't have any question about that. my problem is Javaconfig and @autowired)
Scenario 1:
My CDPlayer Class:
public class CDPlayer implements MediaPlayer {
private CompactDisc cd;
public CDPlayer() {
cd = new CompactDisc() {
@Override
public void play() {
System.out.println("123456");
}
};
}
@Autowired
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
public void play() {
cd.play();
}
}
My JavaConfig File:
@Configuration
public class CDPlayerConfig {
@Bean
public CompactDisc sgtPeppers() {
return new SgtPeppers();
}
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
return new CDPlayer();
}
}
For Example in this scenario, I see that @Autowired is effectless and cannot make Spring to invoke and use the parameterized constructor and no-arg constructor will be executed (because it is invoked in the @Bean method) and the output is the text "123456".
=================================================================
SCENARIO 2:
My JavaConfig File:
@Configuration
public class CDPlayerConfig {
@Bean
public CompactDisc sgtPeppers() {
return new SgtPeppers();
}
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
return new CDPlayer(compactDisc);
}
}
My CDPlayer Class:
public class CDPlayer implements MediaPlayer {
private CompactDisc cd;
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
public void play() {
cd.play();
}
}
we wired those two beans in the config file. and I know that we do not need @Autowired at all.
=================================================================
SCENARIO 3:
My JavaConfig File:
@Configuration
public class CDPlayerConfig {
@Bean()
public CompactDisc sgtPeppers() {
return new SgtPeppers();
}
@Bean
public CDPlayer cdPlayer() {
return new CDPlayer();
}
}
My CDPlayer Class:
public class CDPlayer implements MediaPlayer {
private CompactDisc cd;
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
public void play() {
cd.play();
}
@Autowired
public void setCd(CompactDisc cd) {
this.cd = cd;
}
}
I know that if @Autowired is above of parameterized constructor, that constructor will not be executed but now that is above of setCd(), this method will be executed.
=================================================================
SCENARIO 4:
My JavaConfig File:
@Configuration
public class CDPlayerConfig {
@Bean
public CompactDisc sgtPeppers() {
return new SgtPeppers();
}
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
return new CDPlayer(compactDisc);
}
}
My CDPlayer Class:
public class CDPlayer implements MediaPlayer {
private CompactDisc cd;
public CDPlayer() {
}
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
public void play() {
cd.play();
}
@Autowired
public void doSomething(CompactDisc cd) {
this.cd = new CompactDisc() {
@Override
public void play() {
System.out.println("AAAAA");
}
};
}
}
and in this scenario, Although that we wired those two beans together, but @Autowired makes spring to execute the doSomething()method.
What is happening?! I can't see the Big Picture. I can't understand the pattern that is going on.
sometimes @Autowired works and sometimes doesn't work. what is the general pattern? do we need @Autowired at all when we wire beans together in JavaConfig file?
CodePudding user response:
An autowired constructor is invoked if spring invokes the constructor by reflection, typically because you declare the bean using component scanning or XML config. If you manually invoke a constructor in a @Bean method, that constructor executes, and @Autowired has no effect.
An autowired method is invoked after the bean has been created, irrespective of how the bean was created.
The reason is that, in Java, each constructor call creates a new object, making it impossible to call two constructors for the same object. That's why Spring can't call a second constructor if you have already called a different one. In contrast, it is possible to call many methods on the same object, so Spring does support method autowiring just fine.
To conclude, you can use autowiring with JavaConfig, but you should autowire fields or methods rather than constructors. Or you can do without autowiring, and pass everything explicitly in your @Bean method. Or any mixture of the two.
CodePudding user response:
The Spring Context contains all the beans you need in your program, and Spring do the rest of the job for you. But something to understand is that your beans comes from many parts of your application :
- Internal beans (POJO from your domain).
- External beans (POJO from other libraries or third partie classes).
Reading this from the spring documentation, you can find all the differents sources of beans :
@SpringBootApplication is a convenience annotation that adds all of the following:
@Configuration: Tags the class as a source of bean definitions for the application context.
@EnableAutoConfiguration: Tells Spring Boot to start adding beans based on classpath settings, other beans, and various property settings. For example, if spring-webmvc is on the classpath, this annotation flags the application as a web application and activates key behaviors, such as setting up a DispatcherServlet.
@ComponentScan: Tells Spring to look for other components, configurations, and services in the com/example package, letting it find the controllers.
Follow these rules :
- In your domain classes (Controller, Service) : use
@Autowiredin your constructor. It is the recommanded way to inject your dependencies. - You want to use external classes : implements a
Java Configurationwith@Configurationannotation, to instanciate your external classes instances as beans. - You want to create custom utilities classes : decorate it with
@Component.
