当前位置: 首页>编程语言>正文

springboot kotlin上开发java kotlin springcloud



我为与Kotlin语言创建DSL提供了出色的支持,并为此投入了大量精力 。

此功能现在用于创建gradle构建文件 , 在Spring Webflux中定义路由, 使用kotlinx.html库创建html模板。

在这里,我将演示创建基于kotlin的DSL来表示Cloud Foundry应用清单内容 。

当以yaml文件表示时,清单示例如下所示:

applications:
 - name: myapp
   memory: 512M
   instances: 1
   path: target/someapp.jar
   routes:
     - somehost.com
     - antother.com/path
   envs:
    ENV_NAME1: VALUE1
    ENV_NAME2: VALUE2

这是我要针对的DSL类型:

cf {
    name = "myapp"
    memory = 512(M)
    instances = 1
    path = "target/someapp.jar"
    routes {
        +"somehost.com"
        +"another.com/path"
    }
    envs {
        env["ENV_NAME1"] = "VALUE1"
        env["ENV_NAME2"] = "VALUE2"
    }
}

获得基本结构

让我从一个看起来像这样的简单结构开始:

cf {
    name = "myapp"
    instances = 1
    path = "target/someapp.jar"
}

并希望这种DSL映射到如下所示的结构:

data class CfManifest(
        var name: String = "",
        var instances: Int? = 0,
        var path: String? = null
)

它将转换为带有Lambda表达式的Kotlin函数:

fun cf(init: CfManifest.() -> Unit) {
 ...
}

该参数如下所示:

() -> Unit

是相当不言自明的,是不带任何参数且不返回任何内容的lambda表达式。

我花了一段时间才想到的部分是这个经过修改的lambda表达式,称为带有接收器的Lambda表达式:

CfManifest.() -> Unit

按照我的理解,它有两件事:

1.它在包装函数的范围内定义了接收器类型的扩展函数-在我的情况下是
CfManifest类别

2.现在,lambda表达式中的this表示接收器函数。

鉴于此, cf函数转换为:

fun cf(init: CfManifest.() -> Unit): CfManifest {
    val manifest = CfManifest()
    manifest.init()
    return manifest
}

可以简单地表示为:

fun cf(init: CfManifest.() -> Unit) = CfManifest().apply(init)

所以现在我打电话给:

cf {
    name = "myapp"
    instances = 1
    path = "target/someapp.jar"
}

转换为:

CFManifest().apply {
  this.name = "myapp"
  this.instances = 1
  this.path = "target/someapp.jar"
}

更多DSL

扩展基本结构:

cf {
    name = "myapp"
    memory = 512(M)
    instances = 1
    path = "target/someapp.jar"
    routes {
        +"somehost.com"
        +"another.com/path"
    }
    envs {
        env["ENV_NAME1"] = "VALUE1"
        env["ENV_NAME2"] = "VALUE2"
    }
}

路由和env依次成为CfManifest类上的方法,如下所示:

data class CfManifest(
        var name: String = "",
        var path: String? = null,
        var memory: MEM? = null,
        ...
        var routes: ROUTES? = null,
        var envs: ENVS = ENVS()
) {

    fun envs(block: ENVS.() -> Unit) {
        this.envs = ENVS().apply(block)
    }

    ...

    fun routes(block: ROUTES.() -> Unit) {
        this.routes = ROUTES().apply(block)
    }
}

data class ENVS(
        var env: MutableMap<String, String> = mutableMapOf()
)

data class ROUTES(
        private val routes: MutableList<String> = mutableListOf()
) {
    operator fun String.unaryPlus() {
        routes.add(this)
    }
}

查看routes方法如何将接收器类型为ROUTES的Lambda表达式接受,这使我可以定义如下表达式:

cf {
    ...
    routes {
        +"somehost.com"
        +"another.com/path"
    }
    ...
}

这里的另一个技巧是使用以下方法添加路线:

+"somehost.com"

使用Kotlin约定启用此功能,该约定将特定的方法名称转换为运算符 ,此处为unaryPlus方法。 对我来说很酷的事情是,该运算符仅在ROUTES实例的范围内可见!

利用Kotlin功能的DSL的另一个功能是指定内存的方式,它有两个部分-数字和修饰符2G,500M等。

通过DSL以稍微修改的方式将其指定为2(G)和500(M)。

它的实现方式是使用另一种Kotlin约定,如果一个类具有一个invoke方法,则实例可以通过以下方式调用它:

class ClassWithInvoke() {
    operator fun invoke(n: Int): String = "" + n
}
val c = ClassWithInvoke()
c(10)

因此,在CFManifest类范围内将invoke方法作为Int的扩展功能实现,就可以实现这种DSL:

data class CfManifest(
        var name: String = "",
        ...
) {
    ...
    operator fun Int.invoke(m: MemModifier): MEM = MEM(this, m)
}

就我而言,这纯粹是实验,对于Kotlin和Kotlin DSL来说,我都是新手,因此很可能在此实现中有很多可以改进的地方,欢迎任何反馈和建议。 您可以使用此示例代码在我的github回购玩这里

翻译自: https://www.javacodegeeks.com/2017/07/cloud-foundry-application-manifest-using-kotlin-dsl.html


https://www.xamrdz.com/lan/5xv1962490.html

相关文章: