Я запускаю проект scala, в котором мне нужно выполнить некоторые правила. Правила будут динамически добавляться или удаляться из файла класса scala во время выполнения.
Итак, я хочу, чтобы каждый раз, когда класс правил изменяется, он должен перезагружаться, чтобы получить изменения без остановки процесса выполнения.
Я использовал runtime.getruntime.exec () для его компиляции
и загрузчик классов URL, чтобы получить измененный код из классов
Exec () запускает штрафы. и в классах целевой папки также изменяется, даже когда я использую загрузчик классов URL, не получаю никаких ошибок.
Но это дает мне тот же результат, что и при запуске проекта. Он не дает мне кода модификации.
Ниже приведен код, который я использую.
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...")
}
}
Это основной объектный файл, в котором я создал Akka HTTP для создания API
Он вызовет 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()
}
}
}
Правила импортируются, о чем говорится ниже.
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
Итак, когда я выполняю код и вызываю API, я получаю вывод как
R1
R2
R5
Теперь, не останавливая проект, раскомментирую R3 и R4. И я снова вызову API, Поскольку я снова выполняю код, используя
runtime.getruntime.exec()
он скомпилирует файл и обновит классы в целевом
Итак, я использовал URLClassLoader, чтобы получить новый объект кода модификации.
Но, к сожалению, я всегда получаю тот же результат, что и при запуске проекта.
R1
R2
R5
Ниже ссылка для полного проекта Исходный код




val beanClass = urlClassLoader.loadClass("CompiledRules.RulesList")
val constructor = beanClass.getConstructor()
val beanObj = constructor.newInstance()
Просто создает новый экземпляр уже загруженного класса.
Встроенные загрузчики классов Java всегда проверяют, загружен ли уже класс, перед его загрузкой. loadClass
protected Class<?> loadClass(String name,
boolean resolve)
throws ClassNotFoundException
Загружает класс с указанным двоичным именем. Реализация этого метода по умолчанию ищет классы в следующем порядке: Вызвать findLoadedClass (String) чтобы проверить, был ли уже загружен класс.
Вызовите метод loadClass в загрузчике родительского класса. Если родительский элемент имеет значение NULL, вместо этого используется загрузчик классов, встроенный в виртуальную машину.
Вызовите метод findClass (String), чтобы найти класс.
Чтобы перезагрузить класс, вам нужно будет реализовать свой собственный подкласс ClassLoader, как в это ссылка на сайт
Класс ClassLoader использует модель делегирования для поиска классов и ресурсов. Каждый экземпляр ClassLoader имеет связанный загрузчик родительского класса. При запросе на поиск класса или ресурса экземпляр ClassLoader делегирует поиск класса или ресурса своему загрузчику родительского класса, прежде чем пытаться найти сам класс или ресурс.
Но насколько я понимаю родительский загрузчик классов не знает об этом классе. Только загрузчик классов, созданный OP (если это не так, это может быть причиной проблемы). Разве родительский загрузчик классов как-то кеширует классы своих дочерних элементов?
12.2. Загрузка классов и интерфейсов docs.oracle.com/javase/specs/jls/se7/html/…
Кажется, это не противоречит всему, что я сказал, или я что-то упускаю?
Это именно то, что я читал, когда вы связали это ... Кажется, ничего не говорится о том, что загрузчик родительских классов будет кэшировать классы дочерних элементов или что-то еще. OP создает новый загрузчик классов URL. Загруженные классы должны храниться только в этом загрузчике классов, а OP каждый раз создает новый CL, поэтому их следует читать снова, если они не кэшированы (где именно?).
Но OP создает новый CL для каждого запроса. Где тогда кешируется загруженный класс?