Dependency injection
- The client delegates to call to another object the responsability of providing its dependencies
- Injection types
Constructor injection
Setter injection
XML
<!-- Load properties file -->
<context:property-placeholder location="classpath:sport.properties" />
<bean id="myFortuneService"
class="com.hvitoi.fortune.HappyFortuneService">
</bean>
<bean id="myBaseballCoach"
class="com.hvitoi.coach.BaseballCoach">
<!-- constructor injection-->
<constructor-arg ref="myFortuneService" />
<!-- setter injection. -->
<property name="fortuneService" ref="myFortuneService" />
<!-- set up literal injection -->
<property name="emailAddress" value="[email protected]" />
<!-- set up property file injection -->
<property name="emailAddress" value="${foo.email}" />
</bean>
public class BaseballCoach implements Coach {
private FortuneService fortuneService;
// constructor injection
public BaseballCoach(FortuneService theFortuneService) {
fortuneService = theFortuneService;
}
// setter injection
public void setFortuneService(FortuneService fortuneService) {
System.out.println("CricketCoach inside setter method");
this.fortuneService = fortuneService;
}
// literal injection - get
public String getEmailAddress() {
return emailAddress;
}
// literal injection - set
public void setEmailAddress(String emailAddress) {
System.out.println("CricketCoach inside setter method - setEmailAddress");
this.emailAddress = emailAddress;
}
// Call method of the dependency
@Override
public String getDailyFortune() {
// use my fortuneService
return fortuneService.getFortune();
}
}
Annotations
Autowiring
will automatically inject the dependency with the name provided in the constructor
@Autowired
annotation on such a constructor is no longer necessary if the target bean only defines one constructor to begin with. However, if several constructors are available, at least one must be annotated to teach the container which one to use.
<beans>
<!-- enable component scanning -->
<context:component-scan base-package="com.hvitoi" />
<!-- Load properties file -->
<context:property-placeholder location="classpath:sport.properties" />
</beans>
package com.hvitoi.springdemo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
// @Component annotation registers the class as a spring bean In quote is the bean ID
@Component
public class TennisCoach implements Coach{
// field injection - reflection
@Autowired
@Qualifier("happyFortuneService") // @Qualifier must be specified when there are multiple implementations for a interface. It tells which implementation to pick (by its bean id)
private FortuneService fortuneService;
// Property file injection
@Value("${foo.email}")
private String email;
@Value("${foo.team}")
private String team;
// Default constructor
public TennisCoach() {
System.out.println(">> inside default constructor");
}
// constructor injection
@Autowired
public TennisCoach(@Qualifier("randomFortuneService") FortuneService fortuneService) { // qualifier optional
this.fortuneService = fortuneService;
}
// method injection
@Autowired
public void doSomeCrazyStuff(FortuneService fortuneService) {
System.out.println(">> TennisCoach: inside doSomeCrazyStuff()");
this.fortuneService = fortuneService;
}
// setter injection
@Autowired // Substitute the constructor for dependency injection
public void setFortuneService(FortuneService fortuneService) {
System.out.println(">> TennisCoach: inside setFortuneService");
this.fortuneService = fortuneService;
}
// Call method of the dependency
@Override
public String getDailyFortune() {
return fortuneService.getFortune();
}
}
Java code
@Configuration
//@ComponentScan("com.hvitoi.springdemo")
@PropertySource("classpath:sport.properties") // inject property file
public class SportConfig {
// Register bean
@Bean
public FortuneService sadFortuneService() {
return new SadFortuneService();
}
// Register bean with dependency
@Bean
public Coach swimCoach() {
return new SwimCoach(sadFortuneService());
}
}
public class SwimCoach implements Coach{
private FortuneService fortuneService;
// ---
@Value("${foo.email}")
private String email;
@Value("${foo.team}")
private String team;
public String getEmail() {
return email;
}
public String getTeam() {
return team;
}
// ---
public SwimCoach (FortuneService fortuneService) {
this.fortuneService = fortuneService;
}
@Override
public String getDailyWorkout() {
return "Swim 1000 meters as a warmup.";
}
@Override
public String getDailyFortune() {
return fortuneService.getFortune();
}
}
public class SwimJavaConfigDemoApp {
public static void main(String[] args) {
// read spring config java class
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SportConfig.class);
// get bean from spring container
Coach theCoach = context.getBean("swimCoach", Coach.class);
// call method
System.out.println(theCoach.getDailyWorkout());
System.out.println(theCoach.getDailyFortune());
// close context
context.close();
}
}