2014-12-06 2 views
10

Я разрабатываю компонентный игровой движок в java, прямо сейчас, когда у меня есть изменения в компонентах, которые мне нужны, чтобы перестроить и перезапустить редактор, чтобы изменения вступили в силу (или я могу использовать ограниченный горячий код если приложение работает в режиме отладки).Как интегрировать beanshell

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

Можете ли вы дать мне какие-либо указания о том, как интегрировать интерпретатор beanshell в проект? Я могу вручную отслеживать исходную папку для изменений и кормить обновленные классы Java, но как происходит горячая пересылка?

+0

http://www.beanshell.org/manual/embeddedmode.html –

+0

Интересно, что никто не упоминал OSGi. http://en.wikipedia.org/wiki/OSGi – Yser

ответ

4

Прежде всего, заголовок немного запутан. Вам не нужно интегрировать BeanShell. То, что вы на самом деле нужны:

  1. определить правильную архитектуру
  2. использовать Java Compiler API для работы с классами ява

Архитектура

Допустим, у вас есть графа объектов. Есть много объектов, ссылок и т. Д. Таким образом, будет действительно сложной задачей заменить какой-то экземпляр на новый. Вместо решения этой проблемы вы можете скрыть динамическую часть за «статическим» прокси. Прокси будет обрабатывать все материалы перезагрузки (включая мониторинг исходных папок).

Перед перезагрузкой:

enter image description here

После перезагрузки:

enter image description here

Имея, что сделано, вы можете легко отслеживать изменения и обновить динамическую часть, когда это необходимо.

Java Compiler API

Вместо использования интерпретируемых языков вы можете использовать Java, компилировать его на лету и загрузка с помощью 'Class.forName()'. Существует много разных примеров из-за того, что этот подход был на некоторое время.

Вот некоторые подробности:

+0

Мой вопрос был очень конкретным, как интегрировать * beanshell *, чтобы сделать горячую замену, и никто не ответил на это. Я не хочу вручную перекомпилировать код и вручную управлять динамической перезагрузкой, также стоит отметить, что наличие прокси-сервера между динамическими и статическими частями - это не так, как если бы на конечные устройства возникли дополнительные накладные расходы (включая некоторые старые j2me). –

+0

Ваш ответ выглядит наиболее полным для других людей с подобными проблемами, поэтому я выбираю его для щедрости. –

0

В основном вы хотите реализовать extensibility или плагин шаблон проектирования. Существует несколько способов реализации этого сценария.

Какой бы компонент вы ни выбрали, чтобы разрешить кому-либо перезагрузить модуль, определить интерфейс и реализовать свою собственную реализацию как стандартную.Например, здесь я пытаюсь представить HelloInterface, которые каждая страна может осуществлять и загружать в любое время,

public interface HelloInterface { 

    public String sayHello(String input); 
    .. 
} 

public class HelloImplDefault implements HelloInterface { 

    public String sayHello(String input) { 
     return "Hello World"; 
    } 
} 

Теперь позволяют пользователю добавлять плагин (пользовательскую реализацию) файлы на предварительно сконфигурированные пути. Вы можете использовать файл FileSystemWatcher или фоновый поток для сканирования этого пути и попытаться скомпилировать и загрузить файл.

Для компиляции Java-файл,

private void compile(List<File> files) throws IOException{ 


     JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
     DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>(); 
     StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null); 
     Iterable<? extends JavaFileObject> compilationUnits = fileManager 
      .getJavaFileObjectsFromFiles(files); 
     JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, null, 
      null, compilationUnits); 
     boolean success = task.call(); 
     fileManager.close(); 

} 

Чтобы загрузить файл класса,

private void load(List<File> files) throws MalformedURLException, InstantiationException, IllegalAccessException, ClassNotFoundException{ 

    ClassLoader cl = Thread.currentThread().getContextClassLoader(); 

    for(File f: files){ 
     if(f.getName().endsWith(".class") && !loadedClass.contains(f.getName())){ 
      URL url = f.toURL(); 
      URL[] urls = new URL[]{url}; 
      Object obj = cl.loadClass(f.getName().replace(".class", "")).newInstance(); 
      if(obj instanceof HelloInterface){ 
       HelloProviders.addProvider((HelloInterface)obj); 
       System.out.println("Loaded "+ ((HelloInterface)obj).getProviderName()); 
      }else{ 
       //Add more classes if you want 
      } 
      loadedClass.add(f.getName()); 
     } 
    } 
} 

На данный момент вы можете прочитать пользовательскую реализацию и загруженным в классе системы заряжания. Теперь вы готовы к работе. Для этого подхода есть последствия для безопасности, которые вам нужно изучать в Интернете.

Я реализовал один образец кода и опубликовал его в github, please take a look. Счастливое кодирование!

0

Взгляните на tapestry-ioc инверсионный контейнер управления, который поддерживает live-reloading.

В режиме разработки (tapestry.production-mode = false) вы можете жить, перезагружая свои услуги. Обратите внимание, что при изменении служебного интерфейса вам необходимо перезапустить . Но любые изменения в реализации сервиса, которые не изменяют интерфейс службы, могут быть перезагружены в реальном времени.

 Смежные вопросы

  • Нет связанных вопросов^_^