OK
Spring + Kotlin 1: konfiguracja bez adnotacji

Spring + Kotlin 1: konfiguracja bez adnotacji

Spring + Kotlin 1: konfiguracja bez adnotacji

Spring 5 dodał nowy – bardzo wygodny – sposób konfiguracji naszych aplikacji przy użyciu jedynie prostych funkcji. Owo podejście nie wymaga stosowania adnotacji ani manipulacji bajtkodu.

Co więcej, Spring dostarcza specjalne wsparcie dla Kotlina wykorzystując jego specyficzne mechanizmy, które znacznie upraszczają kod. No i jeśli o kodzie mowa to przyszła nań pora.

Przykład Ogólny

Dla potrzeb naszego przykładu edukacyjnego stworzymy następująca kolekcję typów, która pozwoli nam zobrazować jak wygląda konfiguracji z użyciem Kotlin DSL.

interface I1
interface I2
class Bean1 : I1
class Bean2(dependency:I1) : I2
class Bean3(dependency:I2)

Teraz wystarczy jeden jedyny import :

import org.springframework.context.support.beans

Aby móc napisać jakże czytelny kawałek kodu:

beans {
    bean<Bean1>()
    bean{
         val i1:I1=ref<Bean1>()
         Bean2(i1)
        }
    bean("Bean3"){
    val i2:I2=ref<Bean2>()
      Bean3(i2)
    }
}

Powyższy fragment jest standardowym kodem Kotlina – nie ma w nim żadnej magii a jedynie wykorzystanie doskonałych mechanizmów do tworzenia DSLi w tym języku. Aby lepiej zrozumieć co się dzieje zerknijmy w głąb metod.

fun beans(init: BeanDefinitionDsl.() -> Unit): BeanDefinitionDsl {
    val beans = BeanDefinitionDsl()
    beans.init()
    return beans
}

Cała zabawa z DSLem jest możliwa dzięki zapisowi “init: BeanDefinitionDsl.() -> Unit” , który definiuje BeanDefinitionDsl jako odbiorcę wywołań w lambdzie. Czyli dla przykładu we fragmencie:

beans {
bean<Bean1>()
  ...
}

Tak naprawdę, wywołujemy :

beans { dsl ->
  dsl.bean<Bean1>()
  ...
}

I idąc dalej, metoda bean zaatakuje nas w następujący sposób:

inline fun <reified T : Any> bean(....){....}

Tutaj dzieje się trochę więcej. Generalnie para słów kluczowych “inline”“reified” w sprytny sposób zachowa informacje o typie z generyka w runtime dzięki czemu możliwe będzie utworzenie nowej instancji klasy Bean1. Podobna mechanika kryje się za metodą “ref” .

inline fun <reified T : Any> ref(name: String? = null) : T =  
    when (name) {
        null -> context.getBean(T::class.java)
        else -> context.getBean(name, T::class.java)
}

Zauważ drogi czytelniku/czytelniczko iż zapis “T::class.java” robi coś niesamowitego i wyciąga klasę z generyka. Magia, po prostu magia….

Inicjalizacja

Nasze beany to tak naprawdę zwykły wzorzec builder i tak jak na klasycznym buiderze wołaliśmy “build()” lub coś podobnego na sam koniec by zapieczętować budowę – tak tutaj przekazujemy do budowy springowy kontekst.

val ourInit: BeanDefinitionDsl =beans {...}
    GenericApplicationContext {
    ourInit.initialize(this)
    refresh()
}

I mamy gotowy kontekst springowy!!! Żadnych adnotacji żadnego CGLiba i majstrowania przy bajtkodzie!!! Kotlin i Spring 5 dają nam jeszcze więcej udogodnień o czym opowiemy sobie w kolejnych artykułach.

ul. Jaracza 62
90-251 Łódź
Bitnami