Kotlin 高级编程语言特性代码实例

2021-03-22 10:16:13 浏览数 (1)

定义接口

代码语言:javascript复制
package com.lightsword.biz

/**
 * @author: Jack
 * 2021/3/18 上午1:01
 */
interface IUserAbility {
    fun getUser(biz:String): String
}

使用注解

代码语言:javascript复制
package com.lightsword.biz

import com.lightsword.da.model.BizEnum
import com.lightsword.da.model.DomainAbility
import com.lightsword.da.model.DomainEnum

/**
 * @author: Jack
 * 2021/3/18 上午1:06
 */
@DomainAbility(domain = DomainEnum.USER, biz = BizEnum.BIZ_1)
class Biz1UserAbility : IUserAbility 

实现接口

代码语言:javascript复制
class Biz1UserAbility : IUserAbility {
    override fun getUser(biz:String): String {
        return "$biz user"
    }
}

枚举类

enum class BizEnum

代码语言:javascript复制
package com.lightsword.da.model


/**
 * @author: Jack
 * 2021/3/16 上午11:24
 */
enum class BizEnum {
    /**
     * 业务身份
     */
    BIZ_1,
    BIZ_2,
    NULL,
    ;
}


package com.lightsword.da.model


/**
 * @author: Jack
 * 2021/3/16 上午11:24
 */
enum class DomainEnum {
    /**
     * 领域定义
     */
    USER,
    PRODUCT,
    ORDER,
    ;

}

注解

annotation class DomainAbility

代码语言:javascript复制
package com.lightsword.da.model

import org.springframework.stereotype.Component

/**
 * @author: Jack
 * 2021/3/16 上午11:18
 *
 * 1.Kotlin中的元注解类定义于kotlin.annotation包中,主要有: @Target、@Retention、@Repeatable、@MustBeDocumented 4种元注解
 * 2.相比Java中5种元注解: @Target、@Retention、@Repeatable、@Documented、@Inherited少了 @Inherited元注解。
 * 3.注解类中只能拥有如下类型的参数: 基本数据类型、字符串、枚举、类引用类型、其他的注解类(例如Deprecated注解类中的ReplaceWith注解类)
 */
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
@Component
annotation class DomainAbility(
    /**
     * 能力领域
     */
    val domain: DomainEnum,
    /**
     * 业务身份
     */
    val biz: BizEnum
)

高阶函数与泛型

fun <Ext, R> execute(domain: DomainEnum, biz: BizEnum, clz: Class<Ext>, f: (Ext) -> R): R

代码语言:javascript复制
package com.lightsword.da

import com.lightsword.da.model.BizEnum
import com.lightsword.da.model.DomainEnum
import java.util.concurrent.ConcurrentHashMap

/**
 * @author: Jack
 * 2021/3/16 下午5:02
 *
 * Spring Bean 初始化流程:
1、 Spring 先检查注解注入的bean,并将它们实例化
2、 然后spring初始化bean的顺序是按照xml中配置的顺序依次执行构造
3、 如果某个类实现了ApplicationContextAware接口,会在类初始化完成后调用setApplicationContext()方法:
4、 如果某个类实现了InitializingBean接口,会在类初始化完成后,并在setApplicationContext()方法执行完毕后,调用afterPropertiesSet()方法进行操作
 */
object DomainAbilityInvoker {
    /**
     * DomainAbility 对象实例的内存缓存
     */
    private val DOMAIN_ABILITY_CACHE = ConcurrentHashMap<String, Any>()

    fun <Ext, R> execute(domain: DomainEnum, biz: BizEnum, clz: Class<Ext>, f: (Ext) -> R): R {
        val ext = find(domain, biz, clz)
        return f(ext)
    }

    private fun <Ext> find(domain: DomainEnum, biz: BizEnum, clz: Class<Ext>): Ext {
        val clzName = clz.name
        val domainName = domain.name
        val bizName = biz.name
        val key = genKey(clz, bizName, domainName)
        // 从缓存中获取
        val cachedExtension = DOMAIN_ABILITY_CACHE[key] as Ext
        if (null != cachedExtension) {
            return cachedExtension
        }
        // 缓存中没找到, 那么去 ExtensionPool 里面重新加载一下, key = interfaceName
        val domainAbilityExtensionList = ExtensionPool.getDomainAbilityExtension(clzName)
        val domainAbilityExtension = domainAbilityExtensionList?.find {
            it.domainEnum.name == domainName && it.biz.name == bizName
        }
        val extensionBean = domainAbilityExtension?.beanInstance

        if (null != extensionBean) {
            DOMAIN_ABILITY_CACHE[key] = extensionBean
        }

        return extensionBean as Ext
    }

    private fun <Ext> genKey(clz: Class<Ext>, bizName: String, domainName: String) =
        clz.name   "|"   bizName   "|"   domainName
}

反射

val extensionBeanMap = ctx.getBeansWithAnnotation(DomainAbility::class.java) val beanClazz = bean::class.java val domainAbilityAnno = beanClazz.getAnnotation(DomainAbility::class.java) ?: continue

代码语言:javascript复制
package com.lightsword.da

import com.lightsword.da.model.DomainAbility
import com.lightsword.da.model.DomainAbilityExtension
import org.springframework.beans.factory.InitializingBean
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware
import org.springframework.stereotype.Component
import java.util.concurrent.atomic.AtomicBoolean

/**
 * @author: Jack
 * 2021/3/16 下午5:02
 *
 * Spring Bean 初始化流程:
1、 Spring 先检查注解注入的bean,并将它们实例化
2、 然后spring初始化bean的顺序是按照xml中配置的顺序依次执行构造
3、 如果某个类实现了ApplicationContextAware接口,会在类初始化完成后调用setApplicationContext()方法:
4、 如果某个类实现了InitializingBean接口,会在类初始化完成后,并在setApplicationContext()方法执行完毕后,调用afterPropertiesSet()方法进行操作
 */
@Component
object DomainAbilityLoader : ApplicationContextAware, InitializingBean {

    lateinit var ctx: ApplicationContext

    var ATOMIC_BOOLEAN = AtomicBoolean()

    /**
     * 实现了ApplicationContextAware接口的类会被调用 setApplicationContext() 方法,从而获取到 Spring容器的上下文。
     */
    override fun setApplicationContext(applicationContext: ApplicationContext) {
        this.ctx = applicationContext
    }

    override fun afterPropertiesSet() {
        init()
    }

    fun init() {
        // 防止启动两次
        if (ATOMIC_BOOLEAN.compareAndSet(false, true)) {
            loadDomainAbility(this.ctx)
        }
    }

    private fun loadDomainAbility(ctx: ApplicationContext) {
        synchronized(this) {
            try {
                val domainAbilityExtensionMap = HashMap<String, MutableList<DomainAbilityExtension>>()
                val extensionBeanMap = ctx.getBeansWithAnnotation(DomainAbility::class.java)
                val extensionList = ArrayList(extensionBeanMap.values)

                // 父 ApplicationContext 的处理逻辑
                val parentCtx = ctx.parent
                if (parentCtx != null) {
                    extensionList.addAll(parentCtx.getBeansWithAnnotation(DomainAbility::class.java).values)
                }

                if (extensionList.isEmpty()) {
                    return
                }

                for (bean in extensionList) {
                    val beanClazz = bean::class.java
                    val domainAbilityAnno = beanClazz.getAnnotation(DomainAbility::class.java) ?: continue

                    val domainAbilityExtension = DomainAbilityExtension()
                    domainAbilityExtension.biz = domainAbilityAnno.biz
                    domainAbilityExtension.beanInstance = bean
                    domainAbilityExtension.domainEnum = domainAbilityAnno.domain
                    /**
                     * 代码说明:
                     * var instances: MutableList<DomainAbilityProviderExtensionInstance>?
                     * instances = domainAbilityProviderExtensionInstanceMap[key]
                     * if (instances == null) {
                     *     instances = mutableListOf()
                     * }
                     * instances.add(domainAbilityProviderExtensionInstance)
                     */
                    // key = interfaceName
                    val key = getInterfaceName(beanClazz)
                    val instances = domainAbilityExtensionMap.computeIfAbsent(key, { k -> mutableListOf() })
                    instances.add(domainAbilityExtension)
                }

                // domainAbilityProviderExtensionInstanceMap values 根据优先级排序
                domainAbilityExtensionMap.values.forEach { list ->
                    list.sortBy { it.priority }
                }

                // domainAbilityProviderExtensionInstance 放进 ExtensionInstancePool 中
                ExtensionPool.putAllDomainAbilityExtension(domainAbilityExtensionMap)

            } catch (e: Exception) {
                throw e
            }
        }
    }

    /**
     * 接口名称
     */
    private fun getInterfaceName(beanClazz: Class<*>): String {
        val beanInterface = if (beanClazz.interfaces.isEmpty()) {
            beanClazz.superclass.interfaces[0]
        } else {
            beanClazz.interfaces[0]
        }
        return beanInterface.canonicalName
    }

}

Kotlin与Java互操作

代码语言:javascript复制
package com.lightsword

import com.lightsword.biz.IUserAbility
import com.lightsword.da.DomainAbilityInvoker
import com.lightsword.da.model.BizEnum
import com.lightsword.da.model.DomainEnum
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
import javax.servlet.http.HttpServletRequest

@SpringBootApplication
class Application

fun main(args: Array<String>) {
    runApplication<Application>(*args)
}

@RestController
class HelloController {

    @GetMapping("/hello")
    fun hello(@RequestParam(value = "biz") biz: String, httpRequest: HttpServletRequest): Any {

        val bizEnum = when (biz) {
            "BIZ_1" -> BizEnum.BIZ_1
            "BIZ_2" -> BizEnum.BIZ_2
            else -> BizEnum.NULL
        }

        // fun <Ext, R> execute(domain: DomainEnum, biz: BizEnum, clz: Class<Ext>, f: (Ext) -> R): R
        return DomainAbilityInvoker.execute(
            DomainEnum.USER,
            bizEnum,
            IUserAbility::class.java,
            { iUserAbility -> iUserAbility.getUser(biz) }
        )

    }

}

synchronized 同步锁

代码语言:javascript复制
private fun loadDomainAbility(ctx: ApplicationContext) {
        synchronized(this) {...}
}


/*
 * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
 * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
 */

@file:kotlin.jvm.JvmMultifileClass
@file:kotlin.jvm.JvmName("StandardKt")
package kotlin

import kotlin.contracts.*
import kotlin.jvm.internal.unsafe.*

/**
 * Executes the given function [block] while holding the monitor of the given object [lock].
 */
@kotlin.internal.InlineOnly
public actual inline fun <R> synchronized(lock: Any, block: () -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }

    @Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE", "INVISIBLE_MEMBER")
    monitorEnter(lock)
    try {
        return block()
    }
    finally {
        @Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE", "INVISIBLE_MEMBER")
        monitorExit(lock)
    }
}

Kotlin Contract 契约编程

代码语言:javascript复制
public actual inline fun <R> synchronized(lock: Any, block: () -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    ...
}

关于:contract{ ... } Kotlin 的契约编程, 参考:https://blog.csdn.net/universsky2015/article/details/99011895

0 人点赞