前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Kotlin 高级编程语言特性代码实例

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

作者头像
一个会写诗的程序员
发布2021-03-22 10:16:13
1.2K0
发布2021-03-22 10:16:13
举报

定义接口

代码语言: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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 定义接口
  • 使用注解
  • 实现接口
  • 枚举类
  • 注解
  • 高阶函数与泛型
  • 反射
  • Kotlin与Java互操作
  • synchronized 同步锁
  • Kotlin Contract 契约编程
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档