Комментарии 110
Правда, текста сильно вышло. Можно было сделать короче на 20% — эффект был бы лучше, по-моему.
С аппликэйшн сервером тебе нет необходимости знать где какая база, как к тебе ходят пользователи, по какому протоколу, думать где у тебя продакшен сервер, а где боевой и т.д. ты просто занят бизнес логикой.
По-моему основной плюс спринг бута, единого джара выскакивает когда у тебе необходимо делать сложные веши, например горизонтальное масштабирование проекта
С аппликэйшн сервером тебе нет необходимости знать где какая база, как к тебе ходят пользователи, по какому протоколу, думать где у тебя продакшен сервер, а где боевой и т.д. ты просто занят бизнес логикой.
Да, это только с одной оговоркой — если все заранее настроено, и работает как часы
Речь не про то, что какие-то концепции (сервлеты) — сложные. Скорее про то, что они не нужны в самом начале пути, их можно узнавать постепенно.
А вот для человека, который мало что знает, но хочет «войти в ИТ» и стоит на раздолье: C# | Java | PHP | JS | Python — это будет страшно и не понятно, в конечном случае, выберет то, что будет проще выучить ;-)
И плевать, что WAR и энтерпрайз сервера — это «просто». Новичек не захочет тратить полгода на изучение сервера и всех его внутренностей, чтобы написать свое первое простое приложение. Он захочет «тык-тык и в продакшен!». И он будет прав(((
И цель моей статьи была как раз показать, что чтобы начать — все эти составные части знать не нужно.
Что сложного в сервлете, поставить одну аннотацию и переопределить один метод?..
Когда лично я только убегал из мира Java, ни о каких аннотациях речи не шло — требовалось прописать сервлет в web.xml, притом два раза. Вот на тех, кто навеки запомнил мир Java именно таким, пост и рассчитан.
Да, надо было зарегистрировать сам сервлет и отдельно его маппинг. Ужасен он тем, что его модель — сильно избыточна: зачем вообще придумали сервлеты и маппинги отдельно?
Маппинг — это отображение url на сервлет. Вот этот сервлет обрабатывает вот такие url. И еще вот такие (потенциально — несколько).
Сервлет — это на минутку, сам сервлет. У него есть параметры (настройки). Любые.
Отношение между маппингом и сервлетом — M:1. Я готов согласиться, что это сделано не идеально удобно (я бы наверное сделал маппинг дочерним элементом для сервлета), но что это непонятно — хм. Это может быть непонятно если человек почему-то новичок в веб технологиях вообще. Или если доки совсем не читать.
Вот если бы сделали дочерним элементом — то и файл web.xml был бы и не таким страшным...
Тут дело такое — с самого начала в J2EE предполагалось, что компоненты может настраивать как программист, так и деплоер. И эта роль была предусмотрена, вместе с сервер-специфичными xml дескрипторами для него.
Я не стану утверждать однозначно, но вполне могу себе представить ситуацию, когда деплоеру нужно сконфигурировать только маппинг. Ну т.е. суть в том, что в других сценариях, про которые мы часто не думаем, может быть удобнее и так и эдак.
Только вот в чем проблема — сколько я ни смотрел на формат этого файла, я так и не смог понять в чем тут польза деплоеру от такого формата.
Настраиваемые маппинги возможны только для внешнего API, но не для внутреннего. Потому что при исправлении маппинга нужно как минимум исправить еще и то место, где формируется ссылка. А уж если на правильной иерархии маппингов что-то хитрое завязано — то ее и вовсе при деплое сменить невозможно.
Это действительно сложно для новичка. Когда в одиночку с нуля пытаешься разобраться как запустить свой первый хэлло ворлд то постоянно что-то идёт не так. В интернете огромное количество туториалов разной степени устаревшести. В результате можно запросто потратить несколько дней только на то чтобы получить наконец вожделенную строку в броузере. Все эти war, jar, application server, servlets, jee, spring mvc, tomcat, jboss, glassfish всё это поначалу ужасно непонятно. И каждый апп сервер надо ещё как-то настроить. Spring boot очень всё упрощает.
models.py в джанго — entity в спрингбуте
urls.py и views.py — controller в спрингбуте (маппинг урлов записывается прямо в контроллере)
реализация всяких сложных запросов через джанговский foo.objects.filter() — методы findByBlablabla в спрингбутовских репозиториях
Еще в спрингбуте «искаропки» идет не упомянутый в статье шаблонизатор Thymeleaf, который хоть и отличается по синтаксису от джанговского, но тоже без проблем позволяет использовать условия, циклы и т.п.
А вот по поводу Boot не соглашусь, тут я, увы, из другого лагеря — я считаю, что в наши дни не использовать Boot — это странно. Т.е. допускаю, что для некоторых команд и проектов проще без него, но в среднем по больнице — это именно то, чего не хватало Spring. Чего-то, что просто работает. А уж тем более для начинающих разработчиков.
в наши дни не использовать Boot — это странно
Поддерживаю. И для новичка Spring Boot это то, что надо.
Новичок в это лезть не будет, а потом, столкнувшись с первыми проблемами, типа «что за странная ошибка при старте приложения?» надолго погрязнет в поиске какого-то решение вместо того, чтобы заниматься изучением основ.
С проблемой новичок столкнётся далеко не сразу, к тому времени у него достаточно долго будет работоспособное приложение. Когда он столкнётся с проблемой, он откатит код до последней работающей версии, разберётся, какие изменения сломали код и достаточно быстро либо найдёт решение, либо достигнет похожих результатов другим кодом.
+1. Спринг на мой взгляд и так не слишком сложен, во всяком случае большая его часть.
Но если есть понимание как это все работает, то тут соглашусь с автором, что Spring Boot позволяет получить каркас приложения очень быстро.
И в целом, видеть за обучающей статьей людей, которые могут «злоупотребить» отраслью и пройти собеседование на Senior Java Developer — это немного негативный взгляд на мир. Можно же видеть и по другому — это современная тенденция разработки, что для начинающих разработчиков доступно все больше инструментов, чтобы они могли стать продуктивными с самого начала, выпускать продукт как можно раньше, и параллельно учиться, узнавать сложные концепции шаг за шагом. И мне кажется, это прекрасно как для отрасли, так и для разработчиков.
@Controller
public class IndexController {
final VisitsRepository visitsRepository;
public IndexController(VisitsRepository visitsRepository) {
this.visitsRepository = visitsRepository;
}
...
}
Тут наверное @Autowire потерялся на конструкторе. Чтоб понятнее было.
Аннотация Repository не нужна для CrudRepository и его детей.
Кроме CrudRepository есть еще PagingAndSortingRepository и JpaRepository.
*Не нужна для наследников Repository. Можно так же кастомные репозитории делать, наследуясь прямо от Repository. Если не нужны методы CRUD, к примеру.
И можно заменить конструктор на @Autowired:
Делать @Autowired на полях не рекомендуется. В документации этот момент прописан.
Делать @Autowired на полях не рекомендуется. В документации этот момент прописан.
Что-то не могу найти, не поделитесь ссылкой?
облегчает рефакторинг и написание тестов. Я бы даже сказал наоборот — утруждает.
Мне нужна зависимость? Я пишу одну строку кода поля и ставлю одну аннотацию. Все. Никаких сеттеров, конструкторов, присвоения значений в конструкторе не нужно.
Мне нужно написать тест? Легко — аннотации Mock, @InjectMocks и MockitoAnnotations.initMocks(this) в тестовом классе — и мой объект для юнит-тестирования готов. Никаких лишних телодвижений, меньше кода и усилий. Не понимаю, почему кто-то считает @Autowired над полем плохим тоном, я за несколько лет работы со спрингом так и не нашел объяснения для себя почему так делать плохо, а вот через конструктор — хорошо.
2. Начиная с Java 9 field.setAccessible(true) — будет не всегда доступен (если не будет выключен полностью).
3. Начиная с Java 10 — его собирались выключить полностью или еще больше ограничить.
4. Инжект в поле класса — это прямой путь
5. Инжект в поле класса не дает возможности сделать оптимизацию по кешированию конструкторов (см. метод референс) и заставляет всегда выполнять инжект только через рефлексию.
1. Инжект в приватное поле требует поставить field.setAccessible(true), которые не всегда возможен.
Не всегда — это когда? Я таких случаев не знаю.
2. Начиная с Java 9 field.setAccessible(true) — будет не всегда доступен (если не будет выключен полностью).
3. Начиная с Java 10 — его собирались выключить полностью или еще больше ограничить.
И я почти уверен, что до релиза там будет все как было, так как они поломают кучу библиотек, а backward-compatibility это главная фишка Java. Это все-таки не Unsafe, на backward-compatibility которого можно наплевать, так как он формально не часть спецификации.
4. Чтобы выполнить трифиальный тест — нужно подымать контейнер для того, чтобы заинжектить поле!!!
Не нужно, гуглить в сторону @InjectMocks и MockitoAnnotations.initMocks(this)
5. Инжект в поле класса не дает возможности сделать оптимизацию по кешированию конструкторов (см. метод референс) и заставляет всегда выполнять инжект только через рефлексию.
И чем же это плохо? При setAccessible(true) у вас перформенс будет почти тот же, что и при сеттере. Кеш конструктора сделает оптимизацию вам в лучшем случае на несколько миллисекунд.
TcpServer
из реактора, я могу просто получить в один бин конфиг, передать его в другой метод декларации бина и там на основе этих параметров инстанцировать уже сам сервер. Хотя сам сервер если разобраться ничего не знает о контейнерах. То же и с другими компонентами — хорошо, если они никак не завязаны на инжекшн и могут работать независимо — в этом смысле правильное поведение бина, если он всё зависимости принимает в конструктор и просто не создается без них. Мы так проектируем обычные классы, почему те, что мы используем в контейнере должны чем-то отличаться? К слову в самом спринге всё примерно так и сделано (бут вообще весь состоит из таких конфигураций). Нигде вы не увидите аннотаций @Service
или @Inject
, потому, что всё драйвится внешними конфигами, в свою очередь потому, что это дает возможность гибкости и настриваемости. Не вижу причин, почему мой код не может быть таким.Не всегда — это когда? Я таких случаев не знаю.
Например Java Security Policy позволяет запретить рефлексию (но в этом случае, думаю, весь Spring не будет работать)
если погуглить немного: https://stackoverflow.com/questions/14639753/reflection-security
до релиза там будет все как было, так как они поломают кучу библиотек, а backward-compatibility это главная фишка Java.
С обратной совместимостью будет все хорошо — если запускать приложение «по-старому», все будет работать.
Но если запускать приложения как Модульные — то это уже будет новый функционал и тут уже можно внедрить новые правила, что успешно и сделали.
если погуглить немного: http://in.relation.to/2017/04/11/accessing-private-state-of-java-9-modules/
Не нужно, гуглить в сторону @InjectMocks и MockitoAnnotations.initMocks(this)
Mockito — это замечательная библиотека, не спорю. Именно Mockito и выступает в роли IoC контейнера в тестах. Или если это правильное Spring Boot приложение с тестами, — там будет свой Spring Boot IoC for Tests.
ps: Проблемы тестирования через Mockito достойны целой статьи.
И чем же это плохо? При setAccessible(true) у вас перформенс будет почти тот же, что и при сеттере.
Это замечательный вопрос!
Во-первых, в этом случае приватное поле становится публичным, а это уже минус для оптимизации.
Во-вторых, final поле прекращает быть final, а это в свою очередь значит, что оптимизации, которые связаны с final полями уже не будут работать, а так же, что объект не может быть по-нормальному расшарен между потоками и нужно делать синхронизации.
В-третьих, это нарушение целостности и безопасности, когда приватное поле, вдруг становится публичным в рантайме и используется не через публичный API класса.
К слову, добавлю еще один пункт:
6. Классы, которые используют инъекцию зависимостей в поля (@Inject, @Autowired, Resource etc.) нельзя будет переиспользовать без IoC контейнера. Это не самая большая проблема, но она тоже существует.
this
пишу.А все-таки: зачем вы на собеседованиях интересуетесь про такие страшные детали?
Вопрос не праздный.
1. Собеседование длится всего-то час или около того. Вам больше время некуда потратить?
2. Если разработчик ответил правильно — как этот ответ характеризует его как специалиста и профессионала?
Те компании, которые вопят, что «нет нормальных разработчиков», как правило, не умеют правильно проводить технические интервью. Или умеют, но не хотят – потому что нормальный специалист их технологический стек на тряпки раздерёт вместе с архитектором и тим-лидом, а job security – это страшная сила :)
Дайте угадаю: если кто-то и ответил, то запросил настолько космических денег, что вы его не стали рассматривать.
Выше писал о том, что правильный ответ здесь не важен, к тому же его обычно никто не знает. И лично мне на денежные претензии кандидата глубоко плевать, потому что моя сфера — это исключительно его техническая компетенция.
1. Собеседование длится всего-то час или около того. Вам больше время некуда потратить?
У меня много способов потратить время, но если я провожу интервью, то я трачу время именно на это. Мне нужно максимально быстро получить представление о человеке как о специалисте и коллеге, а этот вопрос не только позволяет в редких случаях выявить человека, который разбирается в нужном мне стеке, но и дает огромное количество материала для обсуждения и понимания уровня кандидата. Лично меня вообще не интересует может ли кандидат засунуть квадратный люк в круглый колодец или знает ли он наизусть все методы
SessionImplementor
, на мой взгляд в первую очередь важны личные качества кандидата и как он себе представляет разработку, насколько он четко мыслит в этом направлении. Всё это можно выяснить начиная с этого вопроса. 2. Если разработчик ответил правильно — как этот ответ характеризует его как специалиста и профессионала?
Вопрос этот очень богат коннотациями, например, он позволяет посмотреть насколько человек представляет как работает язык: кто-то вообще не понимает в чем проблема передать в конструкторы двум классам друг друга. Показывает насколько человек глубоко знает спринг, потому что совершенно не обязательно знать правильный ответ на этот вопрос, чтобы предположить как спринг себя поведет в той или иной ситуации. Если же человек сразу отвечает, то скорее всего он человек прошаренный и можно много времени сэкономить. Опять же, я не требую правильного ответа на этот вопрос, а лишь считаю его хорошим стартом, который всегда дает базу для большинства вопросов, которые я бы хотел задать, особенно если мне нужно очень быстро составить представление о человеке.
Как писать на Spring в 2017
А не пора уже про webflux писать? Пробовали уже использовать? Не хотите про это дело написать?
Как хорошо, что среди легиона «професиональных комментаторов» попадаются люди, конструктивно подходящие к проблемам новичков :)
вникнуть в Spring (пока с этим туго)
Ютуб, ищите доклады Жеки Борисова «Спринг-потрошитель» две части — он там все кишки Спринга выворачивает с разбором и лайфкодингом. Полезно даже если ничего не понятно, просто потому что все с живыми примерами.
Я думаю что я из ЦА статьи (убежал с серверной джавы ещё до массовой распространенности Boot), но мне статья не понравилась, простите.
Дело в том, что я не верю туториалам вида:
Шаг 1: Ставите тулзу-для-проекта/скачиваете этот проект со специального сайта-билдера
Шаг 2: Вот вам hello world!
Потому что для чего-то сложнее чем hello world придется отойти на шаг вправо/влево, а там расстрел и долгие мучительные копания в конфигах незнакомой системы сборки или ещё чего.
То есть вместо объяснения магии Spring, вы показываете как всё типа просто, но вся ваша простота улетучится как только надо будет отойти на шаг влево/вправо. И вместо простоты там будет расстрел похлеще JSP.
Возможно для совсем новичков в Java это будет круто, но я так понимаю статью вы писали как "Гайд для новичков в Spring", но не в Java.
имхо начинать лучше всетаки с общей картины что/зачем, какие данные кто-как-зачем обрабатывает, а уже потом залезать в частности разработки конкретного приложения
По себе заметил интересную особенность: проект на чистом спринге + xml я смог настроить и привести в рабочее состояние быстрее чем аналогичный на boot+java-config.
PS. Сразу отвечу про использование памяти — сам фреймворк съедает примерно 32 Мб памяти. У Дейва Сайера, одного из участников команды Spring Boot есть исследование про потребление памяти Спрингом.
Очень интересно было прочитать эту статью, тем более, что пару месяцев назад я уже экспериментировал с этим.
Вот какие у меня остались вопросы после экспериментов и прочтении статьи. Может это и не совсем вопросы, которые должен задавать новичок, но:
1) Магия конфигурирования сервера
Вот есть у меня PHP. Он обычно стоит за Апачем, или за Nginx. А вот Spring работает сам по себе (хотя его конечно тоже можно запроксировать). Ну вот захотелось мне, чтобы сервер слушал на порту 80. И внезапно выяснилось, что для этого надо запускаться по рутом, а это нехорошо. Я погуглил, советов много, но как-то всё не прямо.
Ну и кроме порта есть и другие настройки. В общем и целом, если хочется что-то подтюнить — то у PHP есть для этого два места: конфиг Апача и php.ini. Там и настройки памяти, и настройки потоков, параллельности и т.д. Я уверен, что всё это можно настраивать и в Spring, но как-то тяжелей тут всё это осмыслить.
2) Магия с базами данных
Когда я читаю, что «будет автоматически создана модель данных (таблицы) в БД», то мне становится как-то неуютно: что-то там происходит автоматически, а мне про это не рассказали.
Конечно, с этим можно разобраться. Но если на PHP я пишу простенькое приложение, то я напишу SELECT да и всё, а тут надо вникать в эту магию и она выглядит не очень просто.
1) Идея Spring во многом — это абстракции. Мы не работает с базой данных напрямую, работаем с абстракцией — база это (теоретически) заменяемая реализация. То же самое и с сервером — мы не настраиваем сервер напрямую, мы используем конфиг файл, по которому потом Spring Boot настроит сервер. Это делается в файле application.properties — там есть целая секция Web Properties (включая порт). И теперь если мы заменим Tomcat на Jetty (а это тривиальное изменение в pom.xml) — то те же настройки будут применены и там.
Настроить именно embedded Tomcat через его конфиг файлы, наверное, тоже можно — но это пример того, как мы будем пытаться заставить Spring делать то, что он не хочет — и вряд ли получится легко и хорошо.
Про root думаю актуально и для Апача, просто он скорее всего уже был установлен (под рутом) и работает как демон — поэтому занимает порт 80.
2) Важный момент — модель будет автоматически создана только в нашем конкретном приложении, т.к. это in-memory база (и считается временной для разработки). При подключении к реальной базе — Spring (точнее, Spring Data, а еще точнее конкретная ORM — Hibernate) может либо создать схему автоматически, либо проверить, что модель энтитей соответствует структуре таблиц. Первый вариант в продакешене, разумеется, никто не использует — все работают с миграциями БД (flyway или liquibase). Второй вполне работает для прототипов или интеграционных тестов.
SELECT и любые другие запросы писать точно так же можно, просто они остались за рамками статьи.
И внезапно выяснилось, что для этого надо запускаться по рутом, а это нехорошо.Так и апач под рутом нужно запускать, чтобы на порту < 1024 слушать. Это не спринг виноват.
Да, Апач старует, как рут, но но запросы обрабатываются в контексте пользователя. Обычно www-data.
Для этого у Апача есть какой-то свой механизм (it uses setuid to switch to user context of specified user in httpd.conf).
Конечно, можно и в Spring написать подобный механизм, но его нужно писать, а там уже есть.
Одна запись в xml не туда — приложение не деплоится, странные исключения в логах, которые в гугле не ищутся, ошибка 404 в любой непонятной ситуации. Туториалы только по одной IDE — Esclipe, ручное создание xml файлов, ручное прописывание каждого контроллера. О Spring Boot слышу впервые из этой статьи, и это то, что мне нужно. Спасибо автору за такую статью! Жду продолжения.
Пробую делать по статье:
— Зависимости перечислил Web,DevTools,JPA,H2,Mustache
— Название указал.
— Скачал .zip, распаковал, в Idea открыл, main — запускается.
class IndexController — вот тут я споткнулся. Предположил что он уже должен быть, но его нету, как и нет 3х папок под модель вью и контролеры которые я ожидал увидеть.
Если сам создаю IndexController.java и копирую его код из статьи, Idea мне почти все идентефикаторы подчеркивает красным и пишет «Cannot resolve symbol».
Я так понимаю, это потому что к файлу который я создал не добавлены нужные import, то есть мысль приходит к тому, что базовые mvc файлы должны были уже быть в этом .zip который я скачал с start.spring.io но их почему то там нет.
Хелп плиз.
По умолчанию Spring Initializr не создает папок под View или контроллеры, он в принципе не навязывает никакую структуру.
Нужные Imports в IDEA можно добавить самому — просто поставить курсор на подчеркнутый символ, нажать Alt+Enter и выбрать 'Import ...'.
Ну и как план Б — исходный код этой статьи доступен на GitHub, вот например реализация IndexController
— https://github.com/alek-sys/spring-demo/blob/master/src/main/java/com/example/demo/IndexController.java
spring.mustache.prefix=classpath:/templates/
spring.mustache.suffix=.html
Видимо в последних версиях Spring Boot + Mustache требуется явно указать путь где искать View и расширение.
Это поменялось в версии 2. Обновил код для Spring Boot 2.
[ERROR] No goals have been specified for this build. You must specify a valid lifecycle phase or a goal in the format <plugin-prefix>: or <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:. Available lifecycle phases are: validate, initialize, generate-sources, process-sources, generate-resources, process-resources, compile, process-classes, generate-test-sources, process-test-sources, generate-test-resources, process-test-resources, test-compile, process-test-classes, test, prepare-package, package, pre-integration-test, integration-test, post-integration-test, verify, install, deploy, pre-clean, clean, post-clean, pre-site, site, post-site, site-deploy. -> [Help 1]
[ERROR]
Если в консоле запускаю ./mvnw package
то просто висит, ничего не происходит.
Когда читаю статьи все выглядит логично, но запустить spring мне пока не удалось ни разу :(
Думаю уже может надо сдаться да пойти начать делать сайт на php, как бы мне не нравилась идеология java но что то не могу я пробиться и сделать на java страницу которую бы было видно через веб.
Консольные приложения освоил, а вот переход на web непробиваемый барьер как будто стоит.
Как писать на Spring в 2017