Bootstrap

kotlin 200行代码开发一个简化版Guice

今天本来打算继续完成系列文章的,不想仓促成文,还得好好构思一下。

今天花一点时间来介绍我的一个开源项目中用kotlin完成的一个mini guice的代码。

写这篇文章目的只为炫耀我最爱的kotlin是有多么简洁高效 :)

首先交代一下背景:

一、mynlp是一个由kotlin编写的中文nlp工具箱,当然里面出了分词还有其他炫酷功能,感兴趣可以了解一下。

二、guice是google开发的一个轻量级IOC容器框架。

三、mynlp中组件服务众多,必须一个IOC容器作为底层,spring太过庞大,早期选择了guice。

四、然后guice又依赖其他多个jar,我只是用到了guice部分功能

五、再然后强迫症犯了,半夜希望去除guice依赖,所以用kotlin原生模拟一个guice的api

所以就诞生了这个无依赖mini guice。

首先看一下mini guice的功能需求:

程序员看示例代码最开心了:


interface DbService{
}

class MysqlService : DbService {

}

@ImplementedBy(ElasticSearchService::class)
interface SearchService

class ElasticSearchService : SearchService {

}

interface BissService{
    fun showService()
}

@Singleton
class BissServiceImpl(
        val dbService: DbService,
        val searchService: SearchService
):BissService{
    override fun showService() {
        println(dbService)
        println(searchService)
    }

}

@Singleton
class SprintUIController(val bissService: BissService){
    fun hi(){
        bissService.showService()
    }
}


fun main() {

    val models = ArrayList()

    models += object : AbstractModule() {
        override fun configure() {
            bind(DbService::class.java).toInstance(MysqlService())
            bind(BissService::class.java).toClass(BissServiceImpl::class.java)
        }
    }

    val injector = createInjector(models)

    val controller = injector.getInstance(SprintUIController::class.java)!!

    controller.hi()

}

看起来和guice的api差不多吧

bind().toInstance() 和 bind().toClass 可以手动绑定。

@ImplementedBy可以在接口上直接指定绑定关系

@Singleton用来直接为单例

最方便的是构造函数自动注入:

class BissServiceImpl(
        val dbService: DbService,
        val searchService: SearchService
)
// 构造函数直接表明需要注入的接口即可

最后 getInstance 为你创建对象和对象的依赖。

当然这些需求能只是能满足内部简单需求,如循环依赖肯定会错误。

这里献上kotlin全部实现代码

如果你的开源项目需要简单IOC支持,但是不想引入依赖,那么来试试吧!