简体   繁体   English

Scala URLClassLoader没有重新加载类文件

[英]Scala URLClassLoader is not reloading class file

I am running a scala project where I need to execute some rules. 我正在运行一个scala项目,需要执行一些规则。 The rules will be dynamically added or removed from scala class file at runtime. 这些规则将在运行时从scala类文件中动态添加或删除。

So, I want whenever the rules class modify, it should reload to get the changes without stopping the execution process. 因此,我希望每当修改规则类时,都应重新加载以获取更改,而无需停止执行过程。

I used runtime.getruntime.exec() to compile it 我使用runtime.getruntime.exec()进行编译

and am URL Class loader to get the modified code from classes 和URL类加载器从类中获取修改后的代码

The exec() run fines. exec()运行正常。 and in target folder classes gets modifies also, even when I am using URL Class Loader, not getting any error. 并且即使在使用URL Class Loader的情况下,目标文件夹中的类也会被修改,不会出现任何错误。

But it is giving me same result which i have on starting of the project. 但这给了我项目启动时的相同结果。 It's not giving me modification code. 它没有给我修改代码。

Below is the code which I am using. 下面是我正在使用的代码。

package RuleEngine

import akka.actor._
import akka.http.scaladsl.Http
import akka.http.scaladsl.server.Directives._
import akka.stream.ActorMaterializer
import akka.util.Timeout

import scala.io.StdIn
import Executor.Compute
import scala.concurrent.{Await, ExecutionContextExecutor}
import scala.concurrent.duration._


object StatsEngine {

def main(args: Array[String]) {

implicit val system: ActorSystem = ActorSystem("StatsEngine")
implicit val materializer: ActorMaterializer = ActorMaterializer()
implicit val executionContext: ExecutionContextExecutor = system.dispatcher

implicit val timeout = Timeout(10 seconds)
val computeDataActor = system.actorOf(Props[Compute],"ComputeData")


val route = {
  post {
    path("computedata"/) {
        computeDataActor ! "Execute"
        complete("done")
      }
    }
  }


val bindingFuture = Http().bindAndHandle(route , "localhost", 9000)

println(s"Server online at http://localhost:9000/\nPress RETURN to stop...")
 }
}

This is the main object file where I have created Akka HTTP to make API's 这是我创建Akka HTTP来创建API的主要目标文件

It will call computeDataActor whose code is below. 它将调用下面的代码的computeDataActor。

package Executor

import java.io.File
import java.net.URLClassLoader

import CompiledRules.RulesList
import akka.actor.Actor

class Compute extends Actor{

  def exceuteRule(): Unit ={
    val rlObj = new RulesList
    rlObj.getClass.getDeclaredMethods.map(name=>name).foreach(println)

    val prcs = Runtime.getRuntime().exec("scalac /home/hduser/MStatsEngine/Test/RuleListCollection/src/main/scala/CompiledRules/RuleList.scala -d  /home/hduser/MStatsEngine/Test/RuleListCollection/target/scala-2.11/classes/")
    prcs.waitFor()

    val fk = new File("/home/hduser/MStatsEngine/Test/RuleListCollection/target/scala-2.11/classes/").toURI.toURL

    val classLoaderUrls = Array(fk)

    val urlClassLoader = new URLClassLoader(classLoaderUrls)

    val beanClass = urlClassLoader.loadClass("CompiledRules.RulesList")

    val constructor = beanClass.getConstructor()

    val beanObj = constructor.newInstance()

    beanClass.getDeclaredMethods.map(x=>x.getName).foreach(println)

  }
  override def receive: Receive ={
    case key:String => {
      exceuteRule()
    }
  }
}

Rules are imported which is mentioned below. 导入规则,如下所述。

package CompiledRules

class RulesList{

  def R1 : Any = {
    return "executing R1"
  }

  def R2 : Any = {return "executing R2"}
//  def R3 : Any = {return "executing R3"}
  //def R4 : Any = {return "executing R4"}
  def R5 : Any = {return "executing R5"}
}//Replace

So, whene i execute code, and on calling API, I will get ouput as 因此,当我执行代码并调用API时,我将得到输出

R1
R2
R5

Now, without stopping the project, I will uncomment R3 and R4. 现在,在不停止项目的情况下,我将取消注释R3和R4。 And I will call API again, As I am executing code again, using 然后我将再次调用API,在我再次执行代码时,使用

runtime.getruntime.exec()

it will compile the file and update classes in target 它将编译文件并更新目标中的类

So, i used URLClassLoader to get new object of modification code. 因此,我使用URLClassLoader来获取修改代码的新对象。

But Unfortunately I am getting same result always which i have on starting of the project 但是不幸的是,我在项目开始时总是得到相同的结果

R1
R2
R5

Below is link for complete project Source Code 以下是完整项目源代码的链接

val beanClass = urlClassLoader.loadClass("CompiledRules.RulesList")
    val constructor = beanClass.getConstructor()
    val beanObj = constructor.newInstance()

Is just creating the newInstance of Already loaded class. 只是创建newInstance的已加载类。

Java's builtin Class loaders always checks if a class is already loaded before loading it. Java的内置类加载器总是在加载类之前检查是否已经加载了一个类。 loadClass loadClass

protected Class<?> loadClass(String name,
             boolean resolve)
                  throws ClassNotFoundException

Loads the class with the specified binary name. 用指定的二进制名称加载类。 The default implementation of this method searches for classes in the following order: Invoke findLoadedClass(String) to check if the class has already been loaded. 此方法的默认实现按以下顺序搜索类:调用findLoadedClass(String) 以检查是否已加载该类。

Invoke the loadClass method on the parent class loader. 在父类加载器上调用loadClass方法。 If the parent is null the class loader built-in to the virtual machine is used, instead. 如果父级为null,则使用虚拟机内置的类加载器。

Invoke the findClass(String) method to find the class. 调用findClass(String)方法以查找类。

To reload a class you will have to implement your own ClassLoader subclass as in this link 要重新加载一个类,您将必须实现自己的ClassLoader子类,如链接所示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM