美文网首页Java 核心技术
Kotlin 高级编程语言特性代码实例

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

作者: 光剑书架上的书 | 来源:发表于2021-03-18 16:17 被阅读0次

    定义接口

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

    使用注解

    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 
    

    实现接口

    class Biz1UserAbility : IUserAbility {
        override fun getUser(biz:String): String {
            return "$biz user"
        }
    }
    

    枚举类

    enum class BizEnum

    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

    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

    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

    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互操作

    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 同步锁

    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 契约编程

    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

    相关文章

      网友评论

        本文标题:Kotlin 高级编程语言特性代码实例

        本文链接:https://www.haomeiwen.com/subject/jecpcltx.html