Генерация и компиляция кода во время выполнения - PullRequest
3 голосов
/ 31 октября 2010

Скажем, у меня есть этот код, который использует некоторые входные данные (например, путь URL), чтобы определить, какой метод запустить, с помощью отражения:

// init
map.put("/users/*", "viewUser");
map.put("/users", "userIndex");

// later
String methodName = map.get(path);
Method m = Handler.class.getMethod(methodName, ...);
m.invoke(handler, ...);

При этом используется отражение, поэтому производительность может быть улучшена. Это можно сделать так:

// init
map.put("/users/*", new Runnable() { public void run() { handler.viewUser(); } });
map.put("/users", new Runnable() { public void run() { handler.userIndex(); } });

// later
Runnable action = map.get(path);
action.run();

Но ручное создание всех этих Runnable имеет свои проблемы. Мне интересно, могу ли я генерировать их во время выполнения? Таким образом, у меня будет входная карта, как в первом примере, и я буду динамически создавать карту из второго примера. Конечно, генерация - это просто вопрос создания строки, но как насчет ее компиляции и загрузки?

Примечание: Я знаю, что повышение производительности настолько мало, что это прекрасный пример преждевременной оптимизации. Поэтому это академический вопрос, меня интересует генерация и компиляция кода во время выполнения.

Ответы [ 4 ]

3 голосов
/ 31 октября 2010

Единственный способ динамически генерировать код - это либо сгенерировать исходный код и скомпилировать его, либо сгенерировать байт-код и загрузить его во время выполнения. Существуют шаблонные решения для первого и библиотеки манипулирования байт-кодом для второго. Без реального случая и некоторого профилирования я не думаю, что вы действительно можете сказать, что будет лучше. С точки зрения обслуживания, я думаю, что рефлексия - лучший вариант из доступных.

2 голосов
/ 05 октября 2011

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

По сути, вы используете API компилятора 1.6, ноиспользуйте «нетрадиционный» способ поиска исходных файлов и записи файлов классов: Compiler занимает Iterable<JavaFileObject>, где вы подключаете свою реализацию с поддержкой памяти, и JavaFileManager, который обрабатывает написание файлов классов, где вы хранитевывод двоичного компилятора в память.

Теперь, когда ваш код скомпилирован, вам нужен только пользовательский ClassLoader, который может читать из вашего байтового кода в памяти и загружать класс с правильным FQCN и т. д.

И, к счастью, все, что кажется готовым;)

1 голос
/ 06 октября 2011

На самом деле, механизм отражения будет генерировать похожие заглушки для внутренних вызовов, если вы вызываете одни и те же методы снова и снова.(Просто используйте одни и те же Method объекты вместо того, чтобы воссоздавать их снова и снова.)

0 голосов
/ 31 октября 2010

Хорошо, вы можете написать код в файл .java, скомпилировать его с помощью javac ( как это сделать ) и загрузить его в Java с помощью Reflection.

Но, возможно, в качестве компромисса вы могли бы также получить объекты Method во время инициализации - так что вам просто нужно будет вызывать метод invoke () для каждого запроса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...