美文网首页
Scala - 反射动态创建方法

Scala - 反射动态创建方法

作者: kikiki5 | 来源:发表于2019-07-06 13:35 被阅读0次

    有时候我们想定义一个字符串的方法,然后通过scala的动态创建class,然后反射调用方法,在很多情景下是在学有用的,比较动态自定义spark的mapParations,当然了,每个人的需求都不一样,但是底层原理是一样的。

    scala 动态反射创建方法

    画饼

    运行

    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
    

    工具类实现

    依赖

    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)
      }
    
    }
    

    相关文章

      网友评论

          本文标题:Scala - 反射动态创建方法

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