👻
MicronautアプリケーションをSpringアプリケーションのように作成する
MicronautにはSpringでお馴染みの @Service
や @Repository
などを使用できる仕組みが用意されている。
この仕組みを使うことでMicronautアプリケーションをSpringアプリケーションのように作成できる。
環境
- Micronaut 3.2.3
- Kotlin 1.6.10
- Java 17
準備
簡単なMicronautアプリケーションを用意する。
Pet.kt
data class Pet(
val name: String
)
PetContoller.kt
import io.micronaut.http.annotation.Body
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Get
import io.micronaut.http.annotation.PathVariable
import io.micronaut.http.annotation.Post
@Controller("/pets")
class PetController(
private val petService: PetService
) {
@Get("/{id}")
fun pet(@PathVariable id: Int): Pet? = petService.findPetById(id)
@Post
fun add(@Body pet: Pet) {
petService.addPet(pet)
}
}
PetService.kt
import jakarta.inject.Singleton
@Singleton
class PetService(
private val petRepository: PetRepository
) {
fun findPetById(id: Int): Pet? = petRepository.findById(id)
fun addPet(pet: Pet) {
petRepository.add(pet)
}
}
PetRepository.kt
import jakarta.inject.Singleton
@Singleton
class PetRepository {
private val pets: MutableList<Pet> = mutableListOf()
fun findById(id: Int): Pet? = pets.getOrNull(id)
fun add(pet: Pet) {
pets.add(pet)
}
}
Springのアノテーションを使って作り直す
以下の依存関係を追加する。
build.gradle.kts
dependencies {
...
kapt("io.micronaut.spring:micronaut-spring-annotation")
kapt("io.micronaut.spring:micronaut-spring-boot")
implementation("org.springframework.boot:spring-boot-starter")
implementation("org.springframework.boot:spring-boot-starter-web")
runtimeOnly("io.micronaut.spring:micronaut-spring-boot")
...
}
各アノテーションを置き換える
PetContoller.kt
- import io.micronaut.http.annotation.Body
- import io.micronaut.http.annotation.Controller
- import io.micronaut.http.annotation.Get
- import io.micronaut.http.annotation.PathVariable
- import io.micronaut.http.annotation.Post
+ import org.springframework.web.bind.annotation.GetMapping
+ import org.springframework.web.bind.annotation.PathVariable
+ import org.springframework.web.bind.annotation.PostMapping
+ import org.springframework.web.bind.annotation.RequestBody
+ import org.springframework.web.bind.annotation.RequestMapping
+ import org.springframework.web.bind.annotation.RestController
- @Controller("/pets")
+ @RestController
+ @RequestMapping("/pets")
class PetController(
private val petService: PetService
) {
- @Get("/{id}")
+ @GetMapping("/{id}")
fun pet(@PathVariable id: Int): Pet? = petService.findPetById(id)
- @Post
- fun add(@Body pet: Pet) {
+ @PostMapping
+ fun add(@RequestBody pet: Pet) {
petService.addPet(pet)
}
PetService.kt
- import jakarta.inject.Singleton
+ import org.springframework.stereotype.Service
- @Singleton
+ @Service
class PetService(private val petRepository: PetRepository) {
PetRepository.kt
- import jakarta.inject.Singleton
+ import org.springframework.stereotype.Repository
- @Singleton
+ @Repository
class PetRepository {
ビルドエラー
これで置き換え終了だが、ビルドするとエラーが出る。
エラー: Cannot apply AOP advice to final class. Class must be made non-final to support proxying: com.example.PetController
public final class PetController {
^
AOPを使うのでfinalクラスを使うとダメっぽい。Kotlinの場合はopenを付与しないといけない。
@RestController
@RequestMapping("/pet")
- class PetController {
+ open class PetController {
毎回openを付与するのは面倒なのでRestControllerアノテーションが付与されたクラスはopenされるようにall-openプラグインを使う。build.gradle.ktsに以下を追加する。
build.gradle.kts
allOpen {
annotation("org.springframework.web.bind.annotation.RestController")
}
これでビルドが成功するようになる。
最終形
PetContoller.kt
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
@RestController
@RequestMapping("/pets")
class PetController(
private val petService: PetService
) {
@GetMapping("/{id}")
fun pet(@PathVariable id: Int): Pet? = petService.findPetById(id)
@PostMapping
fun add(@RequestBody pet: Pet) {
petService.addPet(pet)
}
}
PetService.kt
import org.springframework.stereotype.Service
@Service
class PetService(
private val petRepository: PetRepository
) {
fun findPetById(id: Int): Pet? = petRepository.findById(id)
fun addPet(pet: Pet) {
petRepository.add(pet)
}
}
PetRepository.kt
import org.springframework.stereotype.Repository
@Repository
class PetRepository {
private val pets: MutableList<Pet> = mutableListOf()
fun findById(id: Int): Pet? = pets.getOrNull(id)
fun add(pet: Pet) {
pets.add(pet)
}
}
まとめ
MicronautアプリケーションをSpringアプリケーションのように作成することができた。
Springで作成したコンポーネントをMicronautで再利用するなどができるようになるので、Springユーザーならお試しでMicronautアプリケーション作ってみるのも良いと思う。
Discussion