Pull to refresh

Comments 110

Для новичка статья не очень. Знакомство со спрингом нужно начинать явно не с бута. Для тех, кто со спрингом уже знаком, статья так же не будет полезна, т.к. таких туториалов достаточно на том же spring.io.
Если я правильно понял автора, его цель была развеять миф, что Java for Web — это сложно.
Правда, текста сильно вышло. Можно было сделать короче на 20% — эффект был бы лучше, по-моему.
UFO just landed and posted this here
имхо, но аппликэйшн сервер наоборот убирает сложность от разработчика.
С аппликэйшн сервером тебе нет необходимости знать где какая база, как к тебе ходят пользователи, по какому протоколу, думать где у тебя продакшен сервер, а где боевой и т.д. ты просто занят бизнес логикой.
По-моему основной плюс спринг бута, единого джара выскакивает когда у тебе необходимо делать сложные веши, например горизонтальное масштабирование проекта
С аппликэйшн сервером тебе нет необходимости знать где какая база, как к тебе ходят пользователи, по какому протоколу, думать где у тебя продакшен сервер, а где боевой и т.д. ты просто занят бизнес логикой.

Да, это только с одной оговоркой — если все заранее настроено, и работает как часы

ну если у вас команда разработчиков, причем разного уровня, то более опытные разрабы(девопсы/админы) как раз таки настроят аппликэйшн сервер, а тем же джунам вообще не надо занть что там происходит
Если вокруг меня уже есть команда разработчиков, я буду изучать Spring не по хабрастатьям, а по документации и в беседах с коллегами.

Данная же статья, видимо, рассчитана на тех, кто хочет изучить Spring самостоятельно, соответственно, и сервер приложений поднимать придётся своими руками.
Честно говоря, в своё время меня тоже отпугнула сложность сервлетов, и первый свой web-проект я писал на Vaadin :) Уже потом я осознал необходимость изучения таких низкоуровневых технологий.
«Напишите такую книгу, которую бы вам самим хотелось прочитать» — то же, и со статьей. Я хотел написать статью, которой мне самому не хватало когда-то. Речь в комментарии, о котором идет речь (я его оставил), шла что для новичка это не нужно. Это даже не то, чтобы сложно, это скорее лишний уровень абстракции в самый первый день. Так же, как и деплой WAR-ника на сервер (который же надо поставить и запустить, а мы новички). И там даже ниже в комментариях был вопрос — а как убрать имя WAR из пути? Конечно, мы же все знаем — назвать его root.war. Но я намекну — для человека, который первый раз в жизни видит Tomcat это не так же очевидно.

Речь не про то, что какие-то концепции (сервлеты) — сложные. Скорее про то, что они не нужны в самом начале пути, их можно узнавать постепенно.
Для человека, который имеет опыт и багаж знаний — это действительно не сложно.
А вот для человека, который мало что знает, но хочет «войти в ИТ» и стоит на раздолье: C# | Java | PHP | JS | Python — это будет страшно и не понятно, в конечном случае, выберет то, что будет проще выучить ;-)

И плевать, что WAR и энтерпрайз сервера — это «просто». Новичек не захочет тратить полгода на изучение сервера и всех его внутренностей, чтобы написать свое первое простое приложение. Он захочет «тык-тык и в продакшен!». И он будет прав(((
UFO just landed and posted this here
Здесь вопрос не в сложности, а в количестве новых понятий. Архитип — уже новое. Maven плагин для толстого Jar надо ещё настроить, для тонкого — знать какие зависимости и куда деплоить. Надо смотреть что такое WlidFly и GlassFish, выбирать из них. Получается много не сложных по отдельности составных частей — но все вместе получится не очень просто.

И цель моей статьи была как раз показать, что чтобы начать — все эти составные части знать не нужно.
У java высокая планка в хода по сравнению с другими языками. Чтобы запустить простейшее приложение необходимо сразу разобраться с кучей вещей. Возможность выбора из нескольких вариантов ясности тоже не добавляет. Например надо выбрать сервер, а для человека начинающего изучать web разница и между tomcat с glassfish далеко не очевидна. Новичек посмотрит на этот зоопарк и плюнет уйдя на nodeJs, где сложность растет постепенно.
У меня с NodeJS было как-то все наоборот. Нужно было за день запилить сайтик на NodeJS, которым раньше не пользвоался. В первый же час знакомства, попытка прикрутить фреймворк для нормальной авторизации в веб-приложении, вылилась в очень слабую документацию и чтение исходников этого фреймворка. Сайтик запилил, но после этого еще несколько дней приходил в себя от выгорания. Такой-то постепенный рост сложности, дайте два!
Что сложного в сервлете, поставить одну аннотацию и переопределить один метод?..

Когда лично я только убегал из мира Java, ни о каких аннотациях речи не шло — требовалось прописать сервлет в web.xml, притом два раза. Вот на тех, кто навеки запомнил мир Java именно таким, пост и рассчитан.

UFO just landed and posted this here

Да, надо было зарегистрировать сам сервлет и отдельно его маппинг. Ужасен он тем, что его модель — сильно избыточна: зачем вообще придумали сервлеты и маппинги отдельно?

Не знаю, есть ли это в jee 6, но в jee 7 в web.xml сервлеты можно вообще не прописывать, у меня, например, в одном из тестовых проектов в web.xml заполнено только название проекта. Сами сервлеты в коде помечаются аннотацией WebServlet.
UFO just landed and posted this here
А конфигурацию и не нужно размазывать по куче файлов. Это уже ошибка в архитектуре проекта и она не имеет отношения к конкретной реализации, будь то конфигурирование с помощью аннотаций или xml.
Я больше скажу — сам web.xml не обязателен.
Странный вопрос.

Маппинг — это отображение url на сервлет. Вот этот сервлет обрабатывает вот такие url. И еще вот такие (потенциально — несколько).

Сервлет — это на минутку, сам сервлет. У него есть параметры (настройки). Любые.

Отношение между маппингом и сервлетом — M:1. Я готов согласиться, что это сделано не идеально удобно (я бы наверное сделал маппинг дочерним элементом для сервлета), но что это непонятно — хм. Это может быть непонятно если человек почему-то новичок в веб технологиях вообще. Или если доки совсем не читать.

Вот если бы сделали дочерним элементом — то и файл web.xml был бы и не таким страшным...

Тут дело такое — с самого начала в J2EE предполагалось, что компоненты может настраивать как программист, так и деплоер. И эта роль была предусмотрена, вместе с сервер-специфичными xml дескрипторами для него.


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

Только вот в чем проблема — сколько я ни смотрел на формат этого файла, я так и не смог понять в чем тут польза деплоеру от такого формата.


Настраиваемые маппинги возможны только для внешнего API, но не для внутреннего. Потому что при исправлении маппинга нужно как минимум исправить еще и то место, где формируется ссылка. А уж если на правильной иерархии маппингов что-то хитрое завязано — то ее и вовсе при деплое сменить невозможно.

Это действительно сложно для новичка. Когда в одиночку с нуля пытаешься разобраться как запустить свой первый хэлло ворлд то постоянно что-то идёт не так. В интернете огромное количество туториалов разной степени устаревшести. В результате можно запросто потратить несколько дней только на то чтобы получить наконец вожделенную строку в броузере. Все эти war, jar, application server, servlets, jee, spring mvc, tomcat, jboss, glassfish всё это поначалу ужасно непонятно. И каждый апп сервер надо ещё как-то настроить. Spring boot очень всё упрощает.

UFO just landed and posted this here
На джанго, кстати, очень похоже идеологией. Можно провести простое соответствие:
models.py в джанго — entity в спрингбуте
urls.py и views.py — controller в спрингбуте (маппинг урлов записывается прямо в контроллере)
реализация всяких сложных запросов через джанговский foo.objects.filter() — методы findByBlablabla в спрингбутовских репозиториях

Еще в спрингбуте «искаропки» идет не упомянутый в статье шаблонизатор Thymeleaf, который хоть и отличается по синтаксису от джанговского, но тоже без проблем позволяет использовать условия, циклы и т.п.

UFO just landed and posted this here
Да, для тех, кто знаком со Спрингом читать статью вообще не интересно, целевая аудитория исключительно новички.

А вот по поводу Boot не соглашусь, тут я, увы, из другого лагеря — я считаю, что в наши дни не использовать Boot — это странно. Т.е. допускаю, что для некоторых команд и проектов проще без него, но в среднем по больнице — это именно то, чего не хватало Spring. Чего-то, что просто работает. А уж тем более для начинающих разработчиков.
в наши дни не использовать Boot — это странно

Поддерживаю. И для новичка Spring Boot это то, что надо.

В буте слишком много «магии», которую можно добавить исключительно через зависимости и конфиг application.properties/yml. Во многом за счёт этой магии приложения на буте сейчас набирают популярность. Новичок в это лезть не будет, а потом, столкнувшись с первыми проблемами, типа «что за странная ошибка при старте приложения?» надолго погрязнет в поиске какого-то решение вместо того, чтобы заниматься изучением основ.
Новичок в это лезть не будет, а потом, столкнувшись с первыми проблемами, типа «что за странная ошибка при старте приложения?» надолго погрязнет в поиске какого-то решение вместо того, чтобы заниматься изучением основ.

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

+1. Спринг на мой взгляд и так не слишком сложен, во всяком случае большая его часть.

К сожалению, это современная тенденция разработки. Берем Spring Boot, делаем что-то дома и идем на собеседование на Senior Java Developer. Если у собеседующего такой же опыт со Spring Framework, то собеседование пройдено. А если собеседующий начнет ходить вокруг всего, то печаль-беда для кандидата :)
Но если есть понимание как это все работает, то тут соглашусь с автором, что Spring Boot позволяет получить каркас приложения очень быстро.
Ну я бы все таки так не обобщал, собеседование это вообще сложная и непростая тема, безотносительно технологий и опыта (я, кстати, недавно переводил статью как раз про собеседования в Pivotal).

И в целом, видеть за обучающей статьей людей, которые могут «злоупотребить» отраслью и пройти собеседование на Senior Java Developer — это немного негативный взгляд на мир. Можно же видеть и по другому — это современная тенденция разработки, что для начинающих разработчиков доступно все больше инструментов, чтобы они могли стать продуктивными с самого начала, выпускать продукт как можно раньше, и параллельно учиться, узнавать сложные концепции шаг за шагом. И мне кажется, это прекрасно как для отрасли, так и для разработчиков.
Соглашусь с Вами. Но многие начинающие специалисты не лезут внутрь сложных концепций и это печально.
Но многие начинающие специалисты не лезут внутрь сложных концепций и это печально.

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

А почему не с бута? Голый спринг весьма трудоемко конфигурить. Да, гибкости больше, но гораздо больше вариантов ошибиться в хмл конфигурации во всяких xsi:schemaLocation.
Java config позволяет избежать всех жутких xml'ей, да и погибче будет.

Никогда не понимал, в чем эта жуть. Многословно (иногда) — ну может быть. Не так гибко, как конфигурирование в java — очевидно тоже да, код более гибок, чем статический xml.

xml не дебажится, к примеру. Это обстоятельство вместе с «многословно» и «не гибко» и порождает «жуть». Ну, или как-то так…
Спасибо, просто и достаточно для начала.
@Controller
public class IndexController {

    final VisitsRepository visitsRepository;

    public IndexController(VisitsRepository visitsRepository) {
        this.visitsRepository = visitsRepository;
    }
...
}


Тут наверное @Autowire потерялся на конструкторе. Чтоб понятнее было.
Я нашел что со спринга 4.3 для единственного конструктора необязателен @Autowire. Был не прав.
UFO just landed and posted this here
Аннотация Repository не нужна для CrudRepository и его детей.
Кроме CrudRepository есть еще PagingAndSortingRepository и JpaRepository.

*Не нужна для наследников Repository. Можно так же кастомные репозитории делать, наследуясь прямо от Repository. Если не нужны методы CRUD, к примеру.

И можно заменить конструктор на @Autowired:

Делать @Autowired на полях не рекомендуется. В документации этот момент прописан.
Делать @Autowired на полях не рекомендуется. В документации этот момент прописан.

Что-то не могу найти, не поделитесь ссылкой?
Ссылки сейчас не найду, но общее правило, которому рекомендуют придерживаться и которое сильно облегчает рефакторинг и написание тестов это: если зависимость для вашего компонента обязательна и без нее он не работает, то это должно быть в конструкторе (т.к. это контракт), если это зависимость опциональная, и без нее компонент работает (логгер) — ее можно через property injection. Но вообще кейсов для Property Injection очень мало и с ними надо быть очень осторожным.
Не соглашусь, что @Autowired через сеттер или конструктор
облегчает рефакторинг и написание тестов
. Я бы даже сказал наоборот — утруждает.

Мне нужна зависимость? Я пишу одну строку кода поля и ставлю одну аннотацию. Все. Никаких сеттеров, конструкторов, присвоения значений в конструкторе не нужно.
Мне нужно написать тест? Легко — аннотации Mock, @InjectMocks и MockitoAnnotations.initMocks(this) в тестовом классе — и мой объект для юнит-тестирования готов. Никаких лишних телодвижений, меньше кода и усилий. Не понимаю, почему кто-то считает @Autowired над полем плохим тоном, я за несколько лет работы со спрингом так и не нашел объяснения для себя почему так делать плохо, а вот через конструктор — хорошо.
1. Инжект в приватное поле требует поставить field.setAccessible(true), которые не всегда возможен.
2. Начиная с Java 9 field.setAccessible(true) — будет не всегда доступен (если не будет выключен полностью).
3. Начиная с Java 10 — его собирались выключить полностью или еще больше ограничить.

4. Инжект в поле класса — это прямой путь в ад в мир, где ты не можешь работать с объектом без рефлексии и без контейнеров. Чтобы выполнить трифиальный тест — нужно подымать контейнер для того, чтобы заинжектить поле!!!

5. Инжект в поле класса не дает возможности сделать оптимизацию по кешированию конструкторов (см. метод референс) и заставляет всегда выполнять инжект только через рефлексию.
Спасибо за ответ, но я все равно не вижу преимуществ DI через конструктор вместо инджекта в поле.

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) у вас перформенс будет почти тот же, что и при сеттере. Кеш конструктора сделает оптимизацию вам в лучшем случае на несколько миллисекунд.
Лучше инжекшна через конструктор только вообще без инжекшена. Мой любимый подход — это когда бины полностью отвязаны от контейнера и полностью самодостаточны. Вся контейнерная логика находится в java-конфигурации, которая инстанцирует бины явно с нужными параметрами конструктора, вызовами нужных сеттеров, при помощи билдеров или фабрик, не важно как по большому счету. Все инжекшены на уровне конфигурации. Тем самым мы выносим логику инициализации контекста выполнения и создаем косвенность на уровне конфигурации. Зато нам не важно какие объекты у нас выступают в роли бинов. Как заанотированы их поля или конструкторы. Мы можем тестировать этот бин без какой-либо привязке к инжекшенам вообще и делать бины более нативными для языка. Лично для меня это намного более чисто, гибко и представляется как конструктор, где бины это просто классы, которые мы собираем при помощи конфигурации и можем при желании сделать конфигурации разными, гибкими и настраиваемыми. Т.е. есть у меня есть класс 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 контейнера. Это не самая большая проблема, но она тоже существует.
UFO just landed and posted this here
Я всетаки считаю что прописать стоит ИМХО. Одно слово, зато все понятно что откуда и куда. Хотя я также в гетерах и сетарах все через
this
пишу.
Почему не поставить @Autowire на поле visitsRepository?
Можно, но необязательно. В повых версиях спринг сам разберется. А вообще рекомендуют по возможности @Autowire на конструктор. Так меньше шансов что останется не инициализированными. Но в случае циклических зависимостей не прокатит.
Задавал этот вопрос про циклические зависимости в конструкторе на собеседованиях, чтобы понять уровень кандидата в спринге и вообще желании разбираться в деталях. Обычно люди не очень хорошо понимают как там всё устроено. К слову, спринг это умеет, если например сделать один из бинов лейзи
Я обычно спрашиваю, что будет если в singleton scope bean завайрить session scope bean. И копать глубже как эта магия устроена.
А вот раз уж вы подняли такую тему — а зачем? Я уже давно работаю со Спрингом, но как циклическую зависимость сделать — не знаю. Более того, никогда не делал — и считаю наличие циклической зависимости проблемой дизайна. Т.е. круто, что человек это знает, но вот если не знает, то это о чем говорит?
В реальности обычно этого никто не знает, потому что, во-первых, плохой тон, во-вторых, нужно очень редко. Поэтому когда человек, говорит, что не знает, тогда я спрашиваю: а как вы думаете такое вообще возможно? А если бы вы сами это собирались реализовать? И тд. А некоторые сами пытаются предположить как оно там или предполагают как это можно было бы реализовать. Кто-то говорит, что это бедпрактис. Что бы человек ни сказал, всё дает представление о нем. А ответ: не знаю и даже представить не могу — больше других.
Дайте угадаю: если кто-то и ответил, то запросил настолько космических денег, что вы его не стали рассматривать.

А все-таки: зачем вы на собеседованиях интересуетесь про такие страшные детали?
Вопрос не праздный.
1. Собеседование длится всего-то час или около того. Вам больше время некуда потратить?
2. Если разработчик ответил правильно — как этот ответ характеризует его как специалиста и профессионала?

Те компании, которые вопят, что «нет нормальных разработчиков», как правило, не умеют правильно проводить технические интервью. Или умеют, но не хотят – потому что нормальный специалист их технологический стек на тряпки раздерёт вместе с архитектором и тим-лидом, а job security – это страшная сила :)
Дайте угадаю: если кто-то и ответил, то запросил настолько космических денег, что вы его не стали рассматривать.

Выше писал о том, что правильный ответ здесь не важен, к тому же его обычно никто не знает. И лично мне на денежные претензии кандидата глубоко плевать, потому что моя сфера — это исключительно его техническая компетенция.
1. Собеседование длится всего-то час или около того. Вам больше время некуда потратить?

У меня много способов потратить время, но если я провожу интервью, то я трачу время именно на это. Мне нужно максимально быстро получить представление о человеке как о специалисте и коллеге, а этот вопрос не только позволяет в редких случаях выявить человека, который разбирается в нужном мне стеке, но и дает огромное количество материала для обсуждения и понимания уровня кандидата. Лично меня вообще не интересует может ли кандидат засунуть квадратный люк в круглый колодец или знает ли он наизусть все методы SessionImplementor, на мой взгляд в первую очередь важны личные качества кандидата и как он себе представляет разработку, насколько он четко мыслит в этом направлении. Всё это можно выяснить начиная с этого вопроса.
2. Если разработчик ответил правильно — как этот ответ характеризует его как специалиста и профессионала?

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

это избавится от циклических зависимостей?
Да, опция достаточно смешная. На столько, что на моей памяти никто её не предложил. Обычно люди всё же пытаются решать ту задачу, которую им предложили решить, что часто бывает не менее полезно, чем инициативность.
Как писать на Spring в 2017

А не пора уже про webflux писать? Пробовали уже использовать? Не хотите про это дело написать?
Кстати, за информацию про DevTools отдельное спасибо!
Очень приятно, что моя статья вдохновила Вас на написание этой полезной статьи о Spring. Надеюсь, Ваша статья поможет мне вникнуть в Spring (пока с этим туго).

Как хорошо, что среди легиона «професиональных комментаторов» попадаются люди, конструктивно подходящие к проблемам новичков :)
вникнуть в Spring (пока с этим туго)

Ютуб, ищите доклады Жеки Борисова «Спринг-потрошитель» две части — он там все кишки Спринга выворачивает с разбором и лайфкодингом. Полезно даже если ничего не понятно, просто потому что все с живыми примерами.
UFO just landed and posted this here
Еще посоветую отличное видео про Spring Boot от двух ключевых людей в команде — Andy Wilkinson и Stéphane Nicoll. Правда, видео идет два с половиной часа на английском, но зато там как раз про внутренности Spring Boot, как и что он конфигурит, какие у него могут быть критерии и т.п.
UFO just landed and posted this here
смотрел эту лекцию, нифига она не для новичков в спринге, в начале лекции ещё есть что-то полезное, но потом всё как-то сумбурно-запутанно
UFO just landed and posted this here

Я думаю что я из ЦА статьи (убежал с серверной джавы ещё до массовой распространенности Boot), но мне статья не понравилась, простите.


Дело в том, что я не верю туториалам вида:


Шаг 1: Ставите тулзу-для-проекта/скачиваете этот проект со специального сайта-билдера
Шаг 2: Вот вам hello world!


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


То есть вместо объяснения магии Spring, вы показываете как всё типа просто, но вся ваша простота улетучится как только надо будет отойти на шаг влево/вправо. И вместо простоты там будет расстрел похлеще JSP.


Возможно для совсем новичков в Java это будет круто, но я так понимаю статью вы писали как "Гайд для новичков в Spring", но не в Java.

Поддержу, в свое время сам нарвался на похожие проблемы с туториалами по Spring-Data-REST. Если делаешь все как в туториале — все супер просто и понятно, потом надо чуть-чуть допилить/поменять и оказывается что чтобы это сделать надо наворотить кучу кода, переопределить какие-то методы у оберток, о которых вообще не рассказывалось, состряпать пару не очевидных реализаций каких-то интерфейсов и подсунуть через @Configuration.

имхо начинать лучше всетаки с общей картины что/зачем, какие данные кто-как-зачем обрабатывает, а уже потом залезать в частности разработки конкретного приложения
Вообще это хорошая мысль, может я соберусь продолжить эту статью второй, и пусть на базовом уровне, но объяснить внутренности приложения — типа бинов, конфигурации, автоконфигурации, что делает Boot. Думаю, будет очень полезно. Может даже на этом же приложении рассмотреть, развеять магию и сорвать покровы!
Чтобы развеять магию и сорвать покровы необходимо много и упорно читать исходный код тех фреймворков, которые вы используете.
Ну получается что за последнии 5 лет мало что изменилось :-)
Спасибо автору, статья полезная, особенно в плане получения общего представления как, что и зачем. Для старта самое то, чтобы не испугаться раньше времени )
По себе заметил интересную особенность: проект на чистом спринге + xml я смог настроить и привести в рабочее состояние быстрее чем аналогичный на boot+java-config.
А какие у вас размеры WAR файлов в гигабайтах?
Make JAR, not WAR! Размер JAR с включенным сервером (!) Tomcat, Spring, Spring Data, H2 in-memory DB (пример из этой статьи) — 0.028 Gb (28 Mb). Причем как я уже говорил, кроме этого файла на сервере не нужно ничего (кроме JRE). Так что сарказм, скорее, себя не оправдал :)

PS. Сразу отвечу про использование памяти — сам фреймворк съедает примерно 32 Мб памяти. У Дейва Сайера, одного из участников команды Spring Boot есть исследование про потребление памяти Спрингом.
Я вот, PHP-ник, посматриваю в сторону Java. Появилась нужда использовать некоторые библиотеки, а они нормально написаны под Java, а под PHP — так себе…
Очень интересно было прочитать эту статью, тем более, что пару месяцев назад я уже экспериментировал с этим.

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

1) Магия конфигурирования сервера
Вот есть у меня PHP. Он обычно стоит за Апачем, или за Nginx. А вот Spring работает сам по себе (хотя его конечно тоже можно запроксировать). Ну вот захотелось мне, чтобы сервер слушал на порту 80. И внезапно выяснилось, что для этого надо запускаться по рутом, а это нехорошо. Я погуглил, советов много, но как-то всё не прямо.
Ну и кроме порта есть и другие настройки. В общем и целом, если хочется что-то подтюнить — то у PHP есть для этого два места: конфиг Апача и php.ini. Там и настройки памяти, и настройки потоков, параллельности и т.д. Я уверен, что всё это можно настраивать и в Spring, но как-то тяжелей тут всё это осмыслить.

2) Магия с базами данных
Когда я читаю, что «будет автоматически создана модель данных (таблицы) в БД», то мне становится как-то неуютно: что-то там происходит автоматически, а мне про это не рассказали.
Конечно, с этим можно разобраться. Но если на PHP я пишу простенькое приложение, то я напишу SELECT да и всё, а тут надо вникать в эту магию и она выглядит не очень просто.
Эти вопросы я здесь оставил не столько для того, чтобы кто-то на них ответил, а больше как идею для второй серии по обзору архитектуры Spring'а.
Вопросы очень хорошие.

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 и любые другие запросы писать точно так же можно, просто они остались за рамками статьи.

1) можно сделать перенаправление портов с iptables 80->8080 443->8443.
2) можно запустить Apache Web-server(или что-то другое) как прокси для tomcat

И внезапно выяснилось, что для этого надо запускаться по рутом, а это нехорошо.
Так и апач под рутом нужно запускать, чтобы на порту < 1024 слушать. Это не спринг виноват.
Не совсем так…
Да, Апач старует, как рут, но но запросы обрабатываются в контексте пользователя. Обычно www-data.
Для этого у Апача есть какой-то свой механизм (it uses setuid to switch to user context of specified user in httpd.conf).

Конечно, можно и в Spring написать подобный механизм, но его нужно писать, а там уже есть.
Как раз недавно пытался разобраться с Java Web и Spring в частности.
Одна запись в xml не туда — приложение не деплоится, странные исключения в логах, которые в гугле не ищутся, ошибка 404 в любой непонятной ситуации. Туториалы только по одной IDE — Esclipe, ручное создание xml файлов, ручное прописывание каждого контроллера. О Spring Boot слышу впервые из этой статьи, и это то, что мне нужно. Спасибо автору за такую статью! Жду продолжения.
Вы, похоже, смотрели какие-то древние туториалы. А от привязки к конкретной среде вообще нужно абстрагироваться.
Подписываюсь под каждым предложением, имел аналогичный опыт и возникшие проблемы.
А как написанное приложение задеплоить в Tomcat? Поменял в pom.xml jar на war, в томкате (версия 8.5) через manager app установил полученную war-ку. При обращении к приложению получаю 404 с описанием «The origin server did not find a current representation for the target resource or is not willing to disclose that one exists». С Java Web и Spring никогда не работал.
По идее, просто скоприровать JAR / WAR файл в папку, где лежат WAR / JAR файлы и все. Но нужно учитывать, что во все пути будет добавлено имя файла — если файл называется myapp и определяет роут /index, то полный путь будет /myapp/route. Чтобы пути строились от корня, нужно назвать файл root.jar.
В документации есть отдельная секция. Я обновил код и добавил бранч для деплоймента в Tomcat. Только учитывайте имя приложения (путь будет http://localhost:8888/demo-0.0.1-SNAPSHOT/).
А не подскажете как по человечески добавлять сущность в базу? С возвратом ошибок вдруг чего и т.д. Я то нашел метод save в репозитории он нормально работает, но как вернуть ошибку(на возврат же идет итеребл).
Зависит от ошибок. Обычно если что-то не так JPA бросает исключение, так что проще всего наверное обернуть в try / catch и ловить нужные ошибки.
SpringBoot удобная штука, спору нет. Но и dropwizard.io решает практически те-же задачи, а порог вхождения гораздо ниже.
Сравнение все таки не совсем корректно, Spring Boot это просто конфигурация Spring-a, а Dropwizard преследует другие цели, нежели Spring. Сам по себе Spring не имеет ценности, его инфраструктура — имеет (Spring Cloud / Data / Batch / Integration etc).
На текущий момент я освоил синтаксис java, вот пора освоить первый фрейморк.
Пробую делать по статье:

— Зависимости перечислил 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, вот например реализация IndexControllerhttps://github.com/alek-sys/spring-demo/blob/master/src/main/java/com/example/demo/IndexController.java

Для того чтобы пример работал, нужно добавить в main/resources/application.properties следующие строчки

spring.mustache.prefix=classpath:/templates/
spring.mustache.suffix=.html


Видимо в последних версиях Spring Boot + Mustache требуется явно указать путь где искать View и расширение.
Добавил строчки, все равно не заработал пример, вот такая ошибка в IDEA

[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 непробиваемый барьер как будто стоит.

Рано сдаваться :)


Первая ошибка странная — это от Maven, а Intellij должна запускать приложение напрямую.


А вторая совсем странно, может установка Maven сломана? Что выдает ./mvnw --version и java -version? Под Windows, кстати, нужно запускать mvnw.cmd.

Sign up to leave a comment.

Articles