Чем старше Spring, тем больше контекстов

Чем старше Spring, тем больше контекстов

Видел я и совсем забавные ситуации, когда не очень разбирающийся во всей этой каше конфигураций джуниор, дублировал декларацию бинов, прописывая их и в xml-e и через аннотации (ну так чтобы наверняка).

А где же находится правда? Неужели как всегда посередине? Давайте попробуем разобраться…

Для начала давайте сравним стратегии декларации бинов.

Начнём с классического XML-a: Теперь тоже самое, но при помощи аннотаций Ещё разок, но с конфигурацией на джаве: И наконец тоже самое на груви:

Если сравнивать затраченные усилия, то для данной конфигурации лидируют аннотации (их всего 6 штук, минус сеттер). Но поскольку конфигурация полноценного приложения (а не отдельного модуля), включающее также сторонние библиотеки, не может держаться только на аннотациях, было бы более честно сравнивать между конфигурациями Groovy, Java и XML. Даже без очков видно, что конфигурация на груви лидирует по лаконичности и элегантности, однако мне хотелось бы оставить её на закуску. Тем более, что она пока ещё не допилена до конца.

А пока давайте обсудим недостатки и преимущества того, что было до выхода Spring 4.

Прочитав последнюю строчку, суровые критики уже наверняка сделали себе пометку, мол ага, автор статьи видать не в курсе про Factory Beans, SpEL и всякие хитрые профайлы… Но давайте будем честны, XML в данной таблице заработал и так немало плюсов, и на их фоне этот плюс будет смотреться притянутым за уши. SpEL довольно ограничен, а Factory Beans не являются частью XML-a. И положа руку на сердце, даже самые ярые поклонники XML-a вряд ли выбрали бы его как язык программирования.

Еще один вопрос, который мне часто задают на тренингах: «А почему не перекомпилировать при изменении конфигурации — это плюс? Кто рискнёт на продакшне менять имплементацию бинов не прогнав после этого тесты? А всякие мелочи типа имён, паролей и портов, можно просто держать в проперти файлах, содержимое которых так же можно менять ничего не перекомпилируя».

Тут будет уместно рассказать один случай из моей практики, которой можно озаглавить как-то так:

Как XML с JBoss-ом вечеринку спасли

Несколько лет назад я работал в одной IT компании, в которой, из соображений безопасности, программистам нельзя было подключаться к рабочей среде через удалённый доступ. И вот после очередной трудовой недели, мы пошли отдыхать. Сидим в пабе, время — начало третьего утра, настроение отличное, и вдруг, звонит наш саппорт. Приезжай, говорит, срочно. Продакшн падает.

Знакомая ситуация? Есть много причин не хотеть ехать на работу в пятницу ночью… На мои попытки уговорить его попробовать решить всё по телефону, он твердит, что он только сапорт и единственное, что он умеет делать, это набирать номер телефона того, кого надо вызвать. В итоге он всё-таки согласился прочитать мне эксепшн. Проблема оказалась тривиальная: один из веб-сервисов начал глючить, и бин, который к нему обращался, выкидывал эксэпшн из-за которого падало всё приложение. Видимо, автор бина не ожидал такой засады, и эксепшн не отлавливался. А поскольку раньше такого не случалось, то QA пропустили этот код в продакшн.

Причем я прекрасно знал, что до понедельника сделать ничего нельзя, так как веб сервис не наш, и разговаривать не с кем. Но и оставить все как есть было нельзя, на сервере было еще много других job'ов, которые могли бы прекрасно работать, если бы выкинуть проблематичный бин из контекста. Я не буду углубляться в детали, но уверен, что вы сами можете продумать похожий сценарий. Вопрос в том, как можно поменять конфигурацию по телефону, разговаривая с человеком, который ничего не понимает в коде.

На моё счастье этот бин был прописан в xml-e. Дальше состоялся следующий диалог: «Зайди на комп продакшна, открой папку JBoss/server/default/deploy найди там файл idi.ear и открой его. Что значит, как? Ладно переименуй его в zip и открывай. Отлично, видишь там папка META-INF? В ней есть applicationContext.xml? Зайди в него, найди там SchedulerFactoryBean и чуть ниже есть datacarTrigger. Закомментируй эту строчку. Что значит, как? Неважно, сотри её. Отлично, теперь запиши, закрой, переименуй обратно в ear и включай сервер по-новому.»

Ну и всё, дальше счастливый конец. А теперь представьте, что этот бин был бы прописан в java config… Пришлось бы видимо на работу ехать.

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

Такая архитектора изначально подразумевает, что xml будет лежать вне архива (war, ear), причём там, где до него легко добраться. И скорее всего, в компаниях, где используется такой подход существует целая экосистема, заточенная под такой динамизм, со специальными тестами и ролбэками.

С другой стороны, когда речь идёт о сложных конфигурациях, которые не могут быть сугубо декларативными, работать с XML становится крайне неудобно. Все костыли, придуманные для этого еще в первых версиях Спринга, делают конфигурацию очень запутанной, и её трудно поддерживать . Конфигурация на Java имеет в таких случаях большое преимущество. Все бины, настройки которых требуют определённой бизнес логики, намного правильнее прописывать в ней. Не говоря о том, что для джава разработчика намного приятнее писать Джаву, а не XML.

Еще одно небольшое, но все же преимущество конфигурации на Java — это производительность. Все мы знаем, еще со школы, что «рефлекшн тормозит». А бины, прописанные в XML-e или при помощи аннотаций, будут создаваться именно с его помощью. Если все они синглтоны, то это не так важно: просто немного увеличится время бутсрапа. Однако, если ваша программа постоянно создаёт прототайпы, Reflection не желателен. Ну а с конфигурацией на Java, рефлекшн просто не используется. Бины создаются обычным Java-кодом.

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

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

Кто-то скажет, мол, а вот мы не пользуемся аннотациями вообще: да это не всегда удобно, зато все централизовано. Ну тут одно из двух, либо ваш проект очень маленький, и спринга в нём кот наплакал, либо вся эта «централизованность», не вносит ясности. Огромные XML-ы или Java-конфиги, разобраться в которых может только гроссмейстер по шахматам, в итоге приводят к ещё большей путанице.

Итоги

Все наши классы, которые должны являться бинами Спринга, объявляются и настраиваются аннотациями, красиво раскладываются по пэкэджам и сканируются, по указанию центральной конфигурации. Все бины из сторонних библиотек, и то, что нуждается в сложной конфигурации определяется в Java config. А та часть конфигурации, которая нуждается в динамизме выносится в XML, который, вдобавок можно еще и хранить, как внешний ресурс.

Зачем же нужно было придумывать конфигурацию на Groovy, когда и без нее уже хватало бардака? Груви, конечно сегодня в моде, но разве это причина добавлять ещё одну конфигурацию, увеличивая путаницу? Давайте разберемся в чем его суть?

Конфиг на Groovy

Идея Groovy-конфигурации заключается в том, чтобы заменить всё, кроме аннотаций. Она обладает всеми плюсами XML – ведь это скрипт, и его так же можно держать как внешний ресурс. Более того динамизму может быть еще больше, в потенциале, изменения конфигурации не будут требовать рестарта. С другой стороны, она обладает и всеми плюсами Java-конфига, и более того, код на груви, лаконичней, элегантней и мощнее. Правда, на данном этапе, его еще нельзя в полной мере использовать вместо Java-конфигурации, потому что отсутствует поддержка namespac'ов а ля @EnableAspectJAutoProxy, @EnableAsync и многое другое. Это, конечно, можно решить, настроив все нужные бины в конфигурации, но чтобы не заморачиваться, проще пока оставить Java-конфиг. А вот XML уже можно выкидывать :)

Чувствуя, как от последней фразы сжались кулаки у сторонников XML-а, я предлагаю устроить батл. В синий угол ринга приглашаются все оптимисты, которые не боятся новых технологий, а наоборот пытаются их внедрять, чтобы двигаться вперед самим и двигать свою компанию. Они будут сражаться за максимальный динамизм, за возможность девелоперов делать больше и проще, за Agile-разработку и за технические инновации. В красный угол ринга приглашаются наученные горьким опытом реалисты, которые знают, что произойдёт, когда у всех появится сила. Эти люди сегодня, ценят то, что конфигурация на джаве — Type Safe, а XML не даёт никому возможность наломать дров.

Ну а пока батл продолжается, я рискну высказать своё предположение, чем закончится война против XML-ов. Давайте ещё раз посмотрим на картинку и вспомним, старый фильм:

Шварценеггер, конечно, в итоге победил, но какой ценой…

Ну а если кто захочет продолжить баттл в живую, приходите на мой доклад: Spring the Ripper, кто хочет серьёзно поднять свои навыки — приходите на тренинг Spring for Seniors

📎📎📎📎📎📎📎📎📎📎