Как стать автором
Обновить

Комментарии 24

После добавления Actuator к проекту, Spring Boot опубликует список доступных бинов

Ну, на самом деле публиковать бины в JMX можно было давно, еще до появления Boot. И достаточно легко. И потом какая-нибудь консоль типа hawtio позволяет их удобно смотреть и рулить ими.


Ну т.е. опять же, в этом и в метриках нет никакой магии — это просто сконфигурированные неким стандартным образом и доступные отдельно вещи (типа metrics.dropwizard.io).

Про Спринг Бут недавно Женя Борисов доклад сделал. Вроде бы этот же доклад будет и на следующем Джокере:

https://www.youtube.com/watch?v=8xa0RWMwAOE

https://jokerconf.com/2017/talks/2epnldoaiuqc0iwecmq4ms/

То есть Spring предлагает выбор из программирования на xml и программирования на аннотациях.
А программировать точку сборки на Java нельзя?
Одна реализация на интерфейс в контексте в общем случае мало. Есть ли способ иметь много реализаций на интерфейс?
Можно ли делать локальные контексты?

судя по вопросам вы знаете ответы и то, что они положительные

Spring дает несколько способов сконфигурить контекст, через XML или аннотации. Их даже можно смешивать, в общем-то, хотя не очень приветствуется. Не уверен, что понял вопрос про точку сборки. Имеется в виду, можно ли на Java описать "используй этот класс для регистрации этого бина"? Можно, это и делают классы помеченные @Configuration с помощью методов, помеченных @Bean.


Конечно, реализаций может быть сколько угодно.


Думаю, здесь нужно пояснить что вы имеете в виду под "локальным" контекстом. Иметь "локальный" контейнер DI, в рамках пакета, например? Насколько я знаю — нет, контейнер общий.

А что мешает зарегистрировать вручную сколько угодно контейнеров?

В современных контейнерах основным способом конфигурации является код, а не аннотации или xml.
Это логично — нет никаких оснований писать точку сборки на специальном языке, теряя тьюринг-полноту, поддержку от ide, сопровождаемость и повышая порог вхождения.
Тем более, что имея хорошее API для кода, сделать поддержку любого другого способа конфигурирования не проблема.


Spring бросит исключение, что есть два бина, которые удовлетворяют запросу.

Конечно, реализаций может быть сколько угодно.

И как это сочетается без противоречий?


Думаю, здесь нужно пояснить что вы имеете в виду под "локальным" контекстом

Возможность иметь точки сборки, время жизни которых меньше времени работы приложения. Например для окна с редактором или для обработки конкретного запроса.


PS: Точка сборки, она же Composition Root — объект, отвечающий за композицию компонентов в том или ином контексте. Обычно при ее реализации используется DI-контейнер.
Если я правильно понимаю, Spring реализует точку сборки сам, не давая это сделать программисту.

И как это сочетается без противоречий?

Аннотация Qualifier спасет отца русской демократии!

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

А как эти новые точки сборки конфигурировать?
Аннотации с xml тут не слишком удобны.

Примеры:
0) создать некий класс-контейнер бинов, или загрузить отдельный xml с бинами
1) при создании новой точки указать какие пакеты просканировать
2) при создании новой точки накидать в неё классы-бины

Я для таких вещей предпочитаю новый @Configuration-класс, а дальше AnnotationConfigApplicationContext, причём лучше явно указывать @ComponentScan с отдельный package, чтобы не притащить лишнего.


CDI 1.x в этом плане куда менее приятен в обращении.


Хотя для небольших вещей я последнее время предпочитаю использовать гуглёвый guice.

> И как это сочетается без противоречий?

Есть 2 места уточнения реализации: в определении и в месте вставки. Самое простое — в одном из определений прописать Default. Тогда в месте вставки не будет неопределенности какой бин использовать.

Так же можно создать собственную аннотацию, использовать ее в определении и в месте вставки. Тогда могут существовать и другие реализации того же интерфейса/класса, но они не будут использованы.

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

> Возможность иметь точки сборки, время жизни которых меньше времени работы приложения.

Обычно смотрят на это немного по другому: точка сборки та же, но вот время жизни компонента выставляют через соотвествующий scope. В принципе, получается то же самое. Есть стандартные scope для веб-приложений, можно делать собственные.

> Если я правильно понимаю, Spring реализует точку сборки сам, не давая это сделать программисту.

Основной способ работы со Спрингом сейчас — через аннотации. Либо Component (и специализации), либо сочетание @Configuration/@Bean. Плюс, есть возможность через xml прописать. Я практически уверен, что можно подменить стандартный класс, который это делает, только не вижу особой причины.
Так вот ценность DI тут в том, что это просто механизм общения между нашим кодом и Spring Security. И простой заменой реализации DI на Guice не добиться, чтобы Spring Security тоже начал его использовать. А если в этом новом DI не будет интеграции со всеми библиотеками Spring-а, то и ценность его сильно падает.
Когда говорится про то, чтобы заменить Spring DI на тот же Guice обычно предполагается, что Spring полностью уйдет из проекта. Spring Security – это отличная штука, но часто она бывает избыточной. Особенно с появлением JWT и его популяризацией. Далеко не во многих проектах необходима система ролей и ограничение доступов прям на методах, часто достаточно просто сделать фильтрацию для URI.

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

Более того, создание интерфейса, если у него лишь одна реализация — считается плохой практикой.
Depends on… Если класс используется для внутренних целей – да, это плохая практика, но тут и DI становится не нужным. Но если он нужен для связывания отдельных модулей, то даже с единственной реализацией – это будет хорошая практика.

ps: Spring – это хороший фреймворк, но многие его возводят в «абсолют» и приравнивают Java == Spring, что в корне не верно. Да, на нем можно быстро собрать «шаблонное» приложение и оно будет работать вполне вменяемо по ресурсам и по производительности. Но есть задачи, которые требуют меньшего расхода ресурсов и большей производительности на выходе, в этом случае Spring не стоит использовать.

А, ок, в контексте проекта вообще без Spring замена DI контейнера имеет смысл.


Spring Security это одна из самых непростых и запутанных (может, из-за попытки сделать супер-абстракцию над такой специфической областью, как безопасность?) библиотек. Но здесь она лишь как пример, любая библиотека из экосистемы Spring будет работать через DI, это мысль, что я хотел донести.


Про использование классов vs создание интерфейсов. Идея проста до безобразия — если есть лишь один класс-реализация, который должен управляться DI — для него нет смысла создавать интерфейс, а потом регистрировать бин "для интерфейса А используй класс Б". Его можно инжектить самого по себе. Более того, это даже не будет мешать его замокать в тестах. Т.е. не нужно использовать интерфейсы если того не требует бизнес-логика. Я предупреждал, что мысль примитивная :) Просто иногда можно увидеть огромные файлы бутстраппинга DI которые настраивают 1-1 маппинги из интерфейса на класс, я хотел сказать, что этого можно избежать.


Насчет абсолюта — я не верю в абсолюты вообще. И не думаю, что Spring это one size fits all. Просто хотелось развеять ощущение "магии" фреймворка и показать, что ничего особо магического и сложного там нет. Просто обычный, не самый плохой и достаточно современный фреймворк для разработки на JVM.

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

Приведу пример — в сервисе стоит Transactional, сервис сам по себе — все работает отлично. А потом он начинает имплементить какой-то интерфейс. Вообще левый. И все падает, контекст не находит реализацию.
Почему так просходит — можете посмотреть доклады Жене Борисова.

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

На мой взгляд основная проблема спринга, превращающая его из фреймворка в книгу заклинаний, состоит в повсеместном использовании аннотаций. Аннотации в java были придуманы для определения метаданных в коде. Но строить на их основе некий расширяемый метаязык для определения контекста приложения — это вкорне неверная идея, аннотации для этого не приспособлены. Расставленные в коде аннотации сематнически никем не контролируются, кроме рантайма: @EnableWebMvc я могу вообще поставить на любой объект, не обязательно на @Configuration — никто меня не ограничит.
Есть гораздо более удобные, правильные и открытые способы задания конфигурации контекста без аннотаций, например Guice.
Спринг же пытается всю задачу замести под ковер, оставляя пользователю лишь набор заклинаний и рецептов для описания бизнес логики, которые нужно использовать в определенном порядке, иначе просто не взлетит. Это очень эффектно для демонстраций и презентаций, но в реальных проектах при попытке заглянуть под ковер и что-то там изменить всегда сопряжена с головной болью и геморроем.

Спасибо за адекватную статью. Попробую объяснить, почему я когда-то ушел со спринга и добровольно не вернусь.

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

— инициализация spring-beans по дизайну однопоточна. Поэтому большие приложения на спринге стартуют существенное количество времени и ускорить процесс непросто. На дворе 21 век — если приложение в дев-режиме стартует больше трех секунд, то это негодное приложение.

— в спринге «умеем всё из коробки» имеет неприглядную обратную сторону — длиннющие стектрейсы в spring mvc и очень большие проблемы при желании сделать что-то нестандартное. Приходится лезть в конфигурационный код (да-да, тот самый, который обрабатывает аннотации и читает красивый XML) и надеяться, что у нужного бина разработчики нужный метод сделали protected, а не private.

а можно пример "нестандартного" для которого приходилось лезть и переобределять дебри?

Уже не скажу, давно это было. Но в исходниках спринга я провел времени немало.

Уверен что можно было избежать курения кода почитав документацию… Но конечно курение и чтение друг друга дополняют. За всё время дружбы со Спрингом не было ничего что бы я не смог переопределить.

Мне, как junior'у, статья понравилась, написано кратко и доходчиво, намного лучше чем лопатить килотонны исходников, да и в книгах инфа подустарела, тем более скоро 5 версия выходит.

Пишите еще о Spring'e пожалуйста, например похожие статьи о Spring MVC и про работу с Hibernate, и про сам Hibernate, транзакции, уровни изоляции и т.д. тоже :D
НЛО прилетело и опубликовало эту надпись здесь
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории