Настоящие лиды фиксят баги на продакшене изменением параметров.
(c) один из настоящих лидов.
Все мы прекрасно знаем, что очень многое в любом приложении (да чего уж там - куске кода) определяется параметрами. Крутанул в одну сторону - работает, крутанул в другую - не работает.
Знаем и пользуемся этим. За что иногда хочется оторвать руки.
В большинстве случаев параметры получаются один раз на старте приложенияи и могут быть переопределены только после его рестарта. Однако есть случаи когда параметры необходимо переопределять в runtime и для этого тоже есть инструменты.
Лирическое отступление: Если последняя фраза (про переопределение параметров в runtime) вас смутила, повергла в шок или просто удивила - идите и смотрите как это делается у Netflix на примере Archaius. Дальше вам читать может быть без пользы.
Но не все управляется параметрами.
Бывает так, что подкрутить нужно не только параметры, но и логику.
С логикой все несколько хуже, я бы даже сказал стремновато.
Перекрутить логику можно на заранее заготовленную (другая реализация интерфейса и переключение параметра), но трудно переткнуть на новую - то есть ту которой в рантайме приложения нет.
Я говорю «трудно» потому, что ничего невозможного нет, и для этой задачи в Java например есть OSGI. Вот с этой строчки вы бы наверное уже могли бы на меня накинутся, но потерпите - я и сам не фанат OSGI и прекрасно отдаю себе отчет о том, чего стоит использование таких вот решений и как придется переколбасить архитектуру приложения.
Не хочется OSGI но хочется крутить логику ? Ну ок, тогда читаем дальше.
А читать-то собственно и немного. Идите на гитхаб, я уже все слепил.
Что там ? Там стандартная Jetty c одним сервлетом который принимает один параметр (строковый) и возвращает вам его в некоем обработанном виде. Обработки ошибок и всего что там по идее должно быть там нет.
При запуске приложения нужно указать в аргументы путь к файлику с кодом в котором собственно находится логика (примеры файликов в папке resources).
Дальше собственно самое интересное.
Берем листинг номер 1, сохраняем в файлик, скармливаем приложению на старте - и, вуаля, у нас с вами есть какая-то логика, которая просто будет нам возвращать строку которую передали в приложение.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class StringMirrorImpl implements StringMirror { | |
@Override | |
public String mirror(String input) { | |
return input; | |
} | |
} |
Если нам нужно поменять логику приложения, и, например, сделать реверс строки, то мы пишем код который нам это сделает, и сохраняем его в файлик.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class AAA implements StringMirror { | |
@Override | |
public String mirror(String input) { | |
return new StringBuilder(input).reverse().toString(); | |
} | |
} |
Как это работает ?
Работает это на дефолтных возможностях Groovy по парсингу кода.Ключевой является вот эта строчка кода
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Class aClass = groovyClassLoader.parseClass(sourceCodeSupplier.get()); |
Тут Groovy грузит исходный код из файла и компилирует его.
Внимание! ClassLoader от Groovy кэширует сорсы, так что не стоит удивляться если что-то не прогрузилось, а стоит использовать параметр метода parse которые говорит кэшировать или нет.
Приведение объекта содержащего логику к интерфейсу изначально было сделано сугубо из-за простоты такого подхода, но после, в процессе размышлений я пришел к выводу что так и надо : хочешь менять логику - потрудись хотя бы выделить под нее интерфейс и реализовать его!
Ограничения решения.
Первое и самое главное ограничение - это то что ваша «сменяемая» логика не может тащить за собой зависимости на код которого нет в рантайме. То есть если вы в альтернативной версии логики хотите попользоваться другой библиотекой,эмммм скажем для нарезки изображений, то вы должны протащить ее (при деплое приложения) заблаговременно. Если вас не устраивает подобного рода ограничение - то вам нужно идти на … OSGI.Второе ограничение решения - слабая устойчивость к конфигурационным ошибкам.
Если кто-то скормит в такое место некорректную логику (некомпилируемый код), то логика вашего приложения в этой точке не будет работать. Совсем. Что из этого следует для вас - придумайте сами. Можно предпринять какие-то методы защиты - кэшировать предыдущее значение, откатываться к нему в случае чего, автоматически откатываться на реализацию логики по умолчанию и прочее, но фундаментально это проблемы не решает - это решение плохо защищено. Отсюда вывод и рекомендация - использовать подобного рода решения только для проведения экспериментов и/или дебага.
Третье - Groovy сильно медленнее чистой Java. Если вы хотите вставить это в нагруженный/частоиспользуемый кусок кода, то искренне надеюсь, что вы это делаете по нужде (дебаг) или из профессионального любопытства (контроллируемый эксперимент в полевых условиях). Вывод - окончание эксперимента/отладки должно привести к убиранию такой разводки в коде.
Преимущества решения.
Преимущество первое - реальный боевой код кругом, реальное окружение, реальные данные (если не боитесь их повредить/потерять).
Второе - писать такую логику можно прямо в окружении проекта, потом просто копировать код и подсовывать в приложение.
Преимущество третьв (хипстерское) - синтаксический сахар грувей. Но лично я к нему прохладен.
К исследованию возможности такого решения меня побудили вот эти статьи на хабре (раз и два).
Матчасть.
P.S. и не упарывайтесь, пожалуйста.
P.P.S да, я знаю что есть Java 8 , а в ней Nashorn и все такое. Просто я не люблю JS.
Комментариев нет:
Отправить комментарий