Scala URLClassLoader не перезагружает файл класса

Я запускаю проект 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

Ниже ссылка для полного проекта Исходный код

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
253
1

Ответы 1

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, как в это ссылка на сайт

Но OP создает новый CL для каждого запроса. Где тогда кешируется загруженный класс?

Łukasz 11.12.2018 13:14

Класс ClassLoader использует модель делегирования для поиска классов и ресурсов. Каждый экземпляр ClassLoader имеет связанный загрузчик родительского класса. При запросе на поиск класса или ресурса экземпляр ClassLoader делегирует поиск класса или ресурса своему загрузчику родительского класса, прежде чем пытаться найти сам класс или ресурс.

Sachin Kasaraddi 11.12.2018 20:00

Но насколько я понимаю родительский загрузчик классов не знает об этом классе. Только загрузчик классов, созданный OP (если это не так, это может быть причиной проблемы). Разве родительский загрузчик классов как-то кеширует классы своих дочерних элементов?

Łukasz 12.12.2018 13:07

12.2. Загрузка классов и интерфейсов docs.oracle.com/javase/specs/jls/se7/html/…

Sachin Kasaraddi 12.12.2018 13:33

Кажется, это не противоречит всему, что я сказал, или я что-то упускаю?

Łukasz 13.12.2018 10:26

Это именно то, что я читал, когда вы связали это ... Кажется, ничего не говорится о том, что загрузчик родительских классов будет кэшировать классы дочерних элементов или что-то еще. OP создает новый загрузчик классов URL. Загруженные классы должны храниться только в этом загрузчике классов, а OP каждый раз создает новый CL, поэтому их следует читать снова, если они не кэшированы (где именно?).

Łukasz 13.12.2018 13:12

Другие вопросы по теме