This time, I will summarize how to write Spring DI using Java and Kotlin respectively. The environment is Java 1.8, Kotlin 1.2.31, Spring Boot 2.0.0.RELEASE, Spring 5.0.3.RELEASE.
I will omit the detailed explanation about DI. For more information, see Spring Official References Please read.
There are two main types of DI in Spring, "** Setter injection " and " Constructor injection **". If you search online, you will find the word "Field injection", but it is a term that does not appear in the official reference. For the sake of explanation, this article also uses the term Field injection, but it is essentially the same as Setter injection. The Spring team also recommends Constructor injection because it can guarantee that the dependent objects are non-null and immutable. On the other hand, Setter injection should be used for limited purposes such as resetting dependencies.
In the following, we will summarize how to write each of these "Field injection", "Setter injection", and "Constructor injection" in Java and Kotlin.
Field Injection First, let's talk about Field Injection in Java. Field Injection is expressed by writing like ↓.
@Component
class SampleComponent{
@Autowired
public HogeService hogeService;
@Autowired
public FugaService fugaService;
public void hogehoge(){
hogeService.hoge();
}
public void fugafuga(){
fugaService.fuga();
}
}
Next, in Kotlin, write as ↓.
@Component
class SampleComponent{
@Autowired
lateinit var hogeService: HogeService
@Autowired
lateinit var fugaService: FugaService
/*The following methods are omitted*/
}
Kotlin field variables must be initialized at the time of declaration, so if you want to DI, you need to explicitly indicate that they are lazy initialization with the lateinit modifier. Also, in Field Injection, the value is assigned later, so variable declaration using val is not possible.
Setter Injection Next, if you write setter injection in java, it will be code like ↓.
@Component
class SampleComponent{
private HogeService hogeService;
private FugaService fugaService;
@Autowired
public void setHoge(HogeService hogeService){
this.hogeService = hogeService;
}
@Autowired
public void setFuga(FugaService fugaService){
this.fugaService = fugaService;
}
/*The following methods are omitted*/
}
Similarly, if you write a setter injection in Kotlin, you will get code like ↓.
@Component
class SampleComponent{
private var hogeService: HogeService? = null
@Autowired
set(hogeService){
this.hogeService = hogeService
}
private var fugaService: FugaService? = null
@Autowired
set(fugaService){
this.fugaService = fugaService
}
/*The following methods are omitted*/
/*You can also write like ↓
private lateinit var hogeService: HogeService
private lateinit var fugaService: FugaService
@Autowired
fun setHogeService(hogeService: HogeService){
this.hogeService = hogeService
}
@Autowired
fun setFugaService(fugaService: FugaService){
this.fugaService = fugaService
}
*/
}
In kotlin, getters are automatically generated when a field is declared with val, and getters and setters are automatically generated when a field is declared with var. Therefore, like Field injection, variables are declared with var. Furthermore, since it is necessary to customize the processing of the setter, it is necessary to write set () as shown in the code above. You can also write it in much the same way as Java, as I wrote in the comments.
Constructor Injection Finally, if you write Constructor Injection in Java, the code will look like ↓.
@Component
class SampleComponent{
private final HogeService hogeService;
private final FugaService fugaService;
@Autowired
SampleComponent(HogeService hogeService, FugaService fugaService){
this.hogeService = hogeService;
this.fugaService = fugaService;
}
/*The following methods are omitted*/
}
If you only have one constructor, you can omit @Autowired.
@Component
class SampleComponent{
private final HogeService hogeService;
private final FugaService fugaService;
//If there is only one constructor@Autowired can be omitted
SampleComponent(HogeService hogeService, FugaService fugaService){
this.hogeService = hogeService;
this.fugaService = fugaService;
}
/*The following methods are omitted*/
}
Furthermore, if you use Lombok to automatically generate a constructor, you can express Constructor Injection without declaring the constructor.
@Component
@AllArgsConstructor
class SampleComponent{
private final HogeService hogeService;
private final FugaService fugaService;
//It is automatically generated by Lombok, so you don't have to write a constructor.
/*The following methods are omitted*/
}
Next, if you express Constructor Injection in Kotlin, it will be the code of ↓.
@Component
class SampleComponent(
private val hogeService: HogeService,
private val fugaService: FugaService
){
/*The following methods are omitted*/
}
In Kotlin, there is a grammar called primary constructor, and by writing like ↑, the constructor is automatically generated at compile time. This allows you to represent the Constructor Injection without the Lombok annotations.
https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#using-boot-spring-beans-and-dependency-injection
https://docs.spring.io/spring/docs/5.0.5.RELEASE/spring-framework-reference/core.html#beans-factory-collaborators
Recommended Posts