Scala - 反射動態(tài)創(chuàng)建方法

有時候我們想定義一個字符串的方法,然后通過scala的動態(tài)創(chuàng)建class,然后反射調(diào)用方法,在很多情景下是在學有用的,比較動態(tài)自定義spark的mapParations,當然了,每個人的需求都不一樣,但是底層原理是一樣的。

scala 動態(tài)反射創(chuàng)建方法

畫餅

運行

object CreateTest{
  def main(args: Array[String]): Unit = {
    val cim = ClassCreateUtils("def toUps(str:String):String = str.toUpperCase")
    val value = cim.methods("toUps").invoke(cim.instance, "hello")
    println(value) // method1
    println(cim.invoke("World")) // method2
  }
}

輸出

HELLO
WORLD

工具類實現(xiàn)

依賴

compile group: 'org.scala-lang', name: 'scala-library', version: '2.12.8'
compile group: 'org.scala-lang', name: 'scala-reflect', version: '2.12.8'
compile group: 'org.scala-lang', name: 'scala-compiler', version: '2.12.8'

compile group: 'org.apache.spark', name: 'spark-sql_2.12', version: '2.4.0'
compile group: 'org.apache.spark', name: 'spark-core_2.12', version: '2.4.0'
compile group: 'org.apache.spark', name: 'spark-repl_2.12', version: '2.4.0'

源碼

import java.lang.reflect.Method
import java.util
import java.util.UUID
import scala.reflect.runtime.universe
import scala.tools.reflect.ToolBox

case class ClassInfo(clazz: Class[_], instance: Any, defaultMethod: Method, methods: Map[String, Method]) {
  def invoke[T](args: Object*): T = {
    defaultMethod.invoke(instance, args: _*).asInstanceOf[T]
  }
}

object ClassCreateUtils {
  private val clazzs = new util.HashMap[String, ClassInfo]()
  private val classLoader = scala.reflect.runtime.universe.getClass.getClassLoader
  private val toolBox = universe.runtimeMirror(classLoader).mkToolBox()


  def apply(func: String): ClassInfo = this.synchronized {
    var clazz = clazzs.get(func)
    if (clazz == null) {
      val (className, classBody) = wrapClass(func)
      val zz = compile(prepareScala(className, classBody))
      val defaultMethod = zz.getDeclaredMethods.head
      val methods = zz.getDeclaredMethods
      clazz = ClassInfo(
        zz,
        zz.newInstance(),
        defaultMethod,
        methods = methods.map { m => (m.getName, m) }.toMap
      )
      clazzs.put(func, clazz)
    }
    clazz
  }

  def compile(src: String): Class[_] = {
    val tree = toolBox.parse(src)
    toolBox.compile(tree).apply().asInstanceOf[Class[_]]
  }

  def prepareScala(className: String, classBody: String): String = {
    classBody + "\n" + s"scala.reflect.classTag[$className].runtimeClass"
  }

  def wrapClass(function: String): (String, String) = {
    val className = s"dynamic_class_${UUID.randomUUID().toString.replaceAll("-", "")}"
    val classBody =
      s"""
         |class $className extends Serializable{
         |  $function
         |}
            """.stripMargin
    (className, classBody)
  }

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容