что такое спринг java

Обзор модулей Spring для Java

Авторизуйтесь

Обзор модулей Spring для Java

Рассказывает Мария Багулина

Spring для Java — обширная платформа для создания веб-проектов на Java, состоящая из множества независимых модулей (проектов) для разных задач: от простых веб-приложений до Big Data. Мы рассмотрим, что дают эти модули, какие их основные особенности и для чего их можно использовать.

Что такое Spring?

Spring возник в 2003 году в виде облегчённого аналога платформы для корпоративных приложений Java Enterprise. Он позиционируется как простая в использовании платформа для веб-приложений. Spring поддерживает несколько языков JVM: Java, Kotlin и Groovy.

Spring состоит из большого числа модулей. Среди них есть модули-стартеры, без которых Spring-приложение просто не запустится, а есть также вспомогательные проекты, добавляющие в приложение определённую функциональность: например Spring Data Flow для потоковой обработки данных, Security для безопасности или Cloud для распределённых систем. Такая структура позволяет разработчикам эффективно создавать и поддерживать приложения, используя только нужные инструменты.

Остановимся более подробно на основных модулях Spring и узнаем, для чего их можно использовать.

Несколько слов о Spring Framework

Spring Framework — ядро платформы Spring. Framework неявно используется другими компонентами Spring, например MVC и WebFlux, обеспечивая фундаментальные инструменты для различных архитектур приложений. Мы не будем рассматривать его как отдельный модуль Spring, но перечислим основные характеристики и особенности.

Spring Framework включает:

Spring Boot

Spring Boot — комплексный фреймворк для создания и запуска приложений с минимальными усилиями и настройками. Этот модуль делится на два стека: основанный на API сервлетов Spring MVC и реактивный Spring WebFlux.

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

Spring MVC построен на API сервлетов и использует архитектуру синхронного блокирующего ввода-вывода с моделью «один запрос на поток».

В Spring Boot также можно опционально подключить библиотеку Reactor для создания реактивных систем на JVM.

Характеристики

Для чего используется

Вместе со Spring Boot в проектах обычно используются Spring Security и Cloud. С помощью Spring Boot можно создавать:

Что почитать и с чего начать

Для скоростного погружения в Spring Boot пройдитесь по руководству по быстрому запуску. Также в официальной документации можно найти гайд по созданию приложения с помощью Spring Boot и туториал для написания веб-службы RESTful.

Spring Data

Модуль обеспечивает приложениям доступ к данным через реляционные и нереляционные базы данных (БД), map-reduce фреймворки и облачные сервисы. Spring Data содержит множество подпроектов, предназначенных для определённых СУБД. Среди них есть, например, MySQL, MongoDB, Redis и многие другие. Также можно использовать подмодули, разработанные сообществом Spring для более специфичных баз данных вроде ArangoDB, Google Datastore, Microsoft Azure Cosmos DB и других.

Основной механизм, реализуемый в Spring Data — репозиторий. Это набор интерфейсов, использующих JPA Entity для взаимодействия с данными.

Характеристики

Для чего используется

Spring Data используется везде, где нужен доступ к данным, и легко интегрируется с другими модулями Spring.

Что почитать и с чего начать

Обо всех модулях Spring Data можно почитать в официальной документации.

Spring Cloud

Со Spring Cloud вы сможете легко и быстро создавать шаблоны в распределённых системах. Из примеров таких шаблонов: управление конфигурацией, обнаружение сервисов, интеллектуальная маршрутизация, микропрокси, одноразовые токены и многое другое.

Шаблоны, созданные с помощью Spring Cloud, будут хорошо работать в любой распределённой среде, включая ваш собственный ноутбук, центры обработки данных и PaaS-платформы, такие как Cloud Foundry.

Spring Cloud также состоит из множества подпроектов для разных целей. Так, Spring Cloud Azure интегрирует Spring со службами Azure, Spring Cloud Stream используется для создания управляемых событиями микросервисов (event-driven microservices) и так далее.

Характеристики

Для чего используется

Spring Cloud содержит много полезных инструментов для микросервисов и распределённых систем.

Что почитать и с чего начать

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

Spring Cloud Data Flow

Spring Cloud Data Flow нужен приложениям, в которых используется потоковая передача и пакетная обработка данных.

Фреймворк поддерживает ряд готовых кейсов обработки данных, среди которых ETL, потоковая обработка событий и прогнозная аналитика.

Характеристики

Для чего используется

Spring Cloud Data Flow подойдёт для создания конвейеров потоковой обработки данных — например, чтобы пересылать какие-либо данные в базу и затем удобно анализировать их.

Что почитать и с чего начать

Попробуйте создать микросайт с помощью Spring Cloud Data Flow и ознакомиться с примерами использования.

Spring Security

Spring Security — среда аутентификации, авторизации и контроля доступа. Это стандартный фреймворк, который используется для защиты приложений на основе Spring.

Spring Security предоставляет базовые функции безопасности, которые можно легко расширить для ваших собственных нужд.

Характеристики

Для чего используется

Модуль Security нужен, чтобы обеспечить проверку безопасности и защитить приложение от атак.

Что почитать и с чего начать

На официальном сайте есть небольшое руководство по защите веб-приложения, более подробный гайд с объяснением всех функций и особенностей Spring Security, а также раздел в документации.

Spring Integration

Spring Integration позволяет облегчить обмен сообщениями в приложениях на основе Spring, поддерживает интеграцию с внешними системами и даёт инструменты для обработки данных из разных источников. Один из подпроектов Spring Cloud, Spring Cloud Stream, использует Spring Integration как движок для микросервисов, управляемых событиями.

Характеристики

Для чего используется

Spring Integration подключается к проекту, если вам нужно связать POJO (Plain Old Java Object) с помощью парадигмы обмена сообщениями без внедрения зависимостей (DI). Также Integration позволяет взаимодействовать с внешними системами с помощью адаптеров каналов и шлюзов. Адаптеры каналов используются для односторонней интеграции (отправка или получение), а шлюзы — для сценариев запроса / ответа (входящего или исходящего).

Что почитать и с чего начать

Посмотрите небольшое руководство по созданию приложения, использующего Spring Integration для извлечения данных, их обработки и записи в файл. Также можете изучить более 50 примеров.

Spring Batch

Spring Batch — платформа для разработки пакетных приложений. Spring Batch подойдёт как для простых, так и для более сложных проектов — платформа легко масштабируется и может обрабатывать большие объёмы информации.

Характеристики

Для чего используется

Spring Batch подойдёт для приложений с многократно используемыми функциями, чтобы обрабатывать большие объёмы записей. Среди таких функций — ведение логов и трассировка, управление транзакциями, статистика обработки заданий, перезапуск и пропуск заданий, управление ресурсами и другие.

Что почитать и с чего начать

Гайд по созданию базовой пакетной службы и более 20 примеров использования Spring Batch.

…И ещё немного

Мы перечислили лишь ключевые модули Spring. На самом деле их гораздо больше: например, есть ещё Spring for Android для создания Android-приложений, Spring CredHub для взаимодействия с CredHub-сервером, Spring LDAP и многие другие.

С полным списком проектов Spring можно ознакомиться на официальном сайте.

Источник

Spring Java: основы и уроки для начинающих

Содержание

На сегодняшний день практически для всех приложений используют скриптовый метод программирования – Spring Java. Основное преимущество данного языка заключается в том, что пользователю предоставляется возможность разработать программу в виде простого набора loose-coupled элементов, не привязанных друг к другу.

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

Различные элементы и структуры можно удалять или добавлять в любых местах практически независимо друг от друга. По сути, программу можно разделить таким образом, что она даже не поймет, что управляется с помощью Spring Java. Кроме того, данный скриптовый язык программирования значительно упрощает модульное тестирование, так как элемент, разработанный для контента IoC, достаточно просто инжектировать на ложные взаимосвязи и тем самим проверить функциональность и правильность его описания.

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

Сегодня можно найти по Java Spring учебники в огромном количестве и на различных языках (английском, русском и т. д). Поэтому осилить «Джаву» вы можете и самостоятельно, а мы в этом вам постараемся помочь!

Spring изнутри

Как построена архитектура «Джава спринг» изнутри, наверное, знает далеко не каждый. Поэтому давайте рассмотрим более детально эту конструкцию:

Spring: начало

Если вы только решили начать знакомиться с программированием на «Джава спринг», рекомендуем начинать именно с Java ee Spring (фреймворк). Это один из простейших методов с открытым исходным кодом для данной платформы «Джава». Фреймворк создает последовательную конструкцию, которую можно без проблем применить к большинству задач, что были уже ранее описаны на основе Java. Простота и прозрачность фреймворка позволит вам самостоятельно увидеть ошибки в написании.

Spring можно описать как совокупность нескольких независимых фреймворков, так и более сложных конструкций (фреймворк в фреймворке). Большинство данных структур может функционировать независимо друг от друга, однако они демонстрируют огромный объем работоспособности при совместном запуске приложения. Эти компоненты разделяются на структурные детали комплексных программ в зависимости от их предназначения:

На сегодняшний день для всех фреймворков в «Спринг» предоставляется ряд возможностей:

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

Как сделать простое приложение на Java Spring (фреймворк)

Конфигурацию приложения в Spring можно осуществлять несколькими способами. Одним из наиболее распространенных и достаточно простых считается вынос конфигурации в XML-файл. Этот тип традиционно используют во многих версиях Java Spring. Для начинающих рекомендуем использовать такие инструменты как java (1.5), tomcat (6), ant (1.7), eclipse (3), junit 4x.

Для того чтобы описать простую задачку в Java Spring, необходимо придерживаться такой поочередности:

На этом этапе можно сказать, что вы спешно завершили настройку сетевого окружения. Дальше следует подстроить Spring Java config:

Что же мы сделали в Spring Java? Для чайников некоторыеиз выше перечисленных пунктов будут непонятны, поэтому попробуем описать попроще:

Что такое Java Spring Security и зачем он нужен?

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

Ключевые компоненты Spring Security:

Интеграция Java

Integration Java Spring – это уникальный фреймворк, который включает в себя настройку функций, отвечающих за отправку сообщений. Кроме того, данный объект отвечает за построение действенно-ориентировочной архитектуры:

Spring Hadoop

Java Hibernate

Практически все веб-приложения не могут обойтись без хранения большого количества информации. Как правило, для решения этой проблемы используют различные специальные программы – СУБД и т. д. По структуре организации и частоте использования базы данных можно поделить на несколько подгрупп, и так получилось, что реляционные являются наиболее распространенными. Как правило, описание данных конструкций достаточно большие, и не всегда их рационально использовать.

Для преображення одного класса в другой на Java Hibernate Spring существует несколько специальных генераторов:

Преимущества использования Java Hibernate Spring:

Практика для новичков

Одним из самих простых текстовых проектов на Java Spring является написание приложения «привет». Платформа не требует дополнительной регистрации или каких-либо сложных конструкций и форм на bootstrap. Используем простой html без динамики. И пускай основная форма имеет:

Больше нам ничего не нужно. Переходим к Java Spring. Практика:

Что такое MVC, и каким образом оно связано со Spring

MVC – это собственная платформа «Спринга», которая ориентирована на запросы пользователей. В ней задан статистический вид для всех функций запросно-ориентировочных систем. Задание каждого интерфейса должно быть простым и лаконичным, чтобы пользователь по желанию мог без проблем заново имплементировать приложения. Данная платформа прокладывает прямое подключение к front-end-коду. Все интерфейсы связаны с объектом Servlet API. Благодаря этой взаимосвязи значительно упрощается программирование приложения.

Читайте также:  Что такое юфу в ростове

К наиболее важным интерфейсам можно отнести:

К наиболее важным интерфейсам можно отнести:

Java Spring MVC (model-view-controlle) открывает перед разработчиком много дополнительных возможностей:

Основной пакет

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

Пакет DAO предоставляет JDBC-уровень абстракции, что избавляет от необходимости делать утомительное JDBC-кодирование и разбор базы данных поставщика кодов конкретных ошибок. Кроме того, можно сделать программное, а также декларативное управление транзакциями не только для классов, реализующих интерфейсы, но и для всех ваших Pojos (простых объектов Java).

Пакет ORM обеспечивает интеграцию слоев популярных API для отображения реляционных объектов, включая JDO, Hibernate и Ibatis. Используя пакет ОРМ, вы можете применять все O/R-картографы в сочетании с другими функциями Spring-предложения.

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

Применяя метаданные на уровне исходных текстов, можно включить все виды поведенческой информации в код, например NET-атрибуты.

Веб-пакет Spring обеспечивает основные веб-функции интеграции, такие как многочастная функциональность, инициализация контекстов с применением сервлетов слушателей и контекста веб-ориентированных приложений. Реализация в Spring MVC обеспечивает четкое разделение между моделью кода домена и веб-формой, что позволяет использовать все другие особенности Spring Framework для проверки.

Требования к доменным объектам

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

Вспомогательные группы объектов

Существует несколько дополнительных классов:

Расшифровка основных аббревиатур в Java Spring

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

Сегодня можно найти достаточно много полезной и интересной информации по Java Spring. Уроки, учебники, веб-семинары непременно помогут вам без проблем изучить данный скриптовый язык программирования. Если у вас возникли какие-либо проблемы с написанием приложения, пересмотрите документацию по «Спрингу», в которой авторы достаточно детально описали все требования к структуре «Джава», а также ответили на вопросы, как исправить часто совершаемые ошибки.

Источник

Что такое Spring Framework? От внедрения зависимостей до Web MVC

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

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

Содержание

Примечание переводчика:
Текст статьи весьма большой и в переводе могут остаться неточности несмотря на многократную вычитку текста. Буду благодарен всем за конструктивные замечания.

Введение

Сложность экосистемы Spring

Многие компании используют Spring, однако когда вы захотите узнать об этом фреймворке и перейдете на сайт spring.io, то увидите, что вселенная Spring на самом деле состоит из 21 различных активных проектов. Ой!

Кроме того, если вы начали программировать с помощью Spring в последние пару лет, очень велика вероятность того, что вы перешли непосредственно к Spring Boot или Spring Data.

Однако это руководство касается только одного, самого важного из этих проектов: Spring Framework. Почему?

Потому что важно понимать, что Spring Framework является основой для всех других проектов. Spring Boot, Spring Data, Spring Batch — все это построено поверх Spring.

Это имеет два последствия:

15 минут на чтение этого руководства, которое охватывает самые важные 80% Spring Framework, многократно окупятся в вашей профессиональной карьере.

Что такое Spring Framework?

Краткий ответ:

По сути Spring Framework представляет собой просто контейнер внедрения зависимостей, с несколькими удобными слоями (например: доступ к базе данных, прокси, аспектно-ориентированное программирование, RPC, веб-инфраструктура MVC). Это все позволяет вам быстрее и удобнее создавать Java-приложения.

Только это не очень помогает, не так ли?

К счастью, есть и длинный ответ:

Остальная часть этого руководства.

Основы внедрения зависимостей

Если вы уже знаете, что такое внедрение зависимостей, не стесняйтесь переходить прямо к следующему разделу Контейнер Spring IOC / Dependency Injection. В противном случае читайте дальше.

Что такое зависимость?

Представьте, что вы пишете Java класс, который позволяет вам получить доступ к таблице пользователей в вашей базе данных. Вы бы назвали эти классы DAO (объект доступа к данным) или репозитории. Итак, вы собираетесь написать класс UserDAO.

Ваш класс UserDAO имеет только один метод, который позволяет вам находить пользователей в вашей таблице базы данных по их идентификаторам.

Чтобы выполнить соответствующий SQL запрос, вашему классу UserDAO требуется соединение с базой данных. А в мире Java вы, обычно, получаете соединение с базой данных из другого класса, называемого DataSource. Итак, ваш код теперь будет выглядеть примерно так:

Внедрение зависимостей с помощью new()

Наивным решением было бы просто создать новый источник данных с помощью конструктора, каждый раз, когда он вам нужен. Итак, для подключения к базе данных MySQL ваш UserDAO может выглядеть так:

Это работает, но давайте посмотрим, что произойдет, когда мы расширим наш класс UserDao другим методом, findByFirstName.

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

Этот подход работает, но имеет два недостатка:

Что произойдет, если мы хотим создать новый класс ProductDAO, который также выполняет операторы SQL? Ваш ProductDAO также будет иметь зависимость DataSource, которая теперь доступна только в вашем классе UserDAO. Затем у вас будет другой подобный метод или извлечен вспомогательный класс, содержащий ваш DataSource.

Мы создаем совершенно новый источник данных для каждого запроса SQL. Учтите, что DataSource открывает реальное сокет-соединение от вашей Java-программы к вашей базе данных. Это занимает время и довольно дорого. Было бы намного лучше, если бы мы открыли только один источник данных и использовали его повторно, вместо того, чтобы открывать и закрывать их тонны. Одним из способов сделать это может быть сохранение источника данных в закрытом поле в нашем UserDao, чтобы его можно было повторно использовать между методами, но это не помогает при дублировании между несколькими DAO.

Зависимости в глобальном классе приложения

Чтобы решить эти проблемы, вы можете подумать о написании глобального класса Application, который выглядит примерно так:

Ваш класс UserDAO теперь может выглядеть так:

Это улучшение по двум направлениям:

Однако у этого решения есть еще несколько недостатков:

Инверсия управления (IoC, Inversion of Control)

Давайте сделаем еще один шаг вперед.

Было бы неплохо, если бы вам в классе UserDAO вообще не приходилось беспокоиться о поиске зависимостей? Вместо того, чтобы активно вызывать Application.INSTANCE.dataSource(), ваш UserDAO мог бы (как-то) кричать, что он ему нужен, но больше не контролирует, когда / как / откуда он его получает?

Это то, что называется инверсией управления (Inversion of Control).

Давайте посмотрим, как может выглядеть наш класс UserDAO, с новым конструктором.

С точки зрения UserDao это выглядит намного лучше. Он больше не знает ни о классе приложения, ни о том, как создавать сами источники данных. Он только объявляет миру, что «если вы хотите создать (то есть использовать) меня, вам нужно дать мне источник данных».

Но представьте, что вы хотите запустить свое приложение. Если раньше вы могли вызывать «new UserService()», то теперь вам нужно обязательно вызвать новый UserDao(dataSource).

Контейнеры для внедрения зависимостей

Следовательно, проблема в том, что вы, как программист, все еще создаете UserDAO с помощью их конструктора и, таким образом, устанавливаете зависимость DataSource вручную.

Разве не было бы хорошо, если бы кто-то знал, что ваш UserDAO имеет зависимость от конструктора DataSource, и знал, как ее создать? А затем волшебным образом сконструирует для вас оба объекта: работающий DataSource и работающий UserDao?

Этот кто-то является контейнером внедрения зависимостей и является именно тем, что представляет собой среда Spring.

Контейнер Spring IOC / Dependency Injection

Как уже упоминалось в самом начале, Spring Framework по своей сути является контейнером внедрения зависимостей, который управляет написанными вами классами и их зависимостями для вас (см. Предыдущий раздел). Давайте выясним, как это происходит.

Что такое ApplicationContext? Для чего тебе это?

Тот, кто контролирует все ваши классы и может управлять ими соответствующим образом (читай: создайте их с необходимыми зависимостями), называется ApplicationContext во вселенной Spring.

Чего мы хотим добиться, так это следующего кода (я описал UserDao и DataSource в предыдущем разделе, перейдите по ссылке, если вы пришли сюда и пропустили его):

Это довольно круто, не правда ли? Вам, как вызывающей стороне, больше не нужно беспокоиться о создании классов, вы можете просто попросить ApplicationContext предоставить вам рабочие классы!

Но как это работает?

Что такое ApplicationContextConfiguration? Как построить ApplicationContexts из конфигураций.

В приведенном выше коде мы помещаем переменную с именем someConfigClass в конструктор AnnotationConfigApplicationContext. Вот быстрое напоминание:

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

Этого класса конфигурации уже достаточно для запуска самого первого приложения Spring.

Теперь давайте выясним, что именно Spring и AnnotationConfigApplicationContext делают с тем классом конфигурации, который вы написали.

Почему мы создали AnnotationConfigApplicationContext? Существуют ли другие классы ApplicationContext?

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

Посмотрите на класс MyApplicationContextConfiguration сверху. Это класс Java, который содержит аннотации Spring. Вот почему вам необходимо создать аннотацию AnnotationConfigApplicationContext.

Если вместо этого вы хотите создать свой ApplicationContext из файлов XML, вы должны создать ClassPathXmlApplicationContext.

Есть и много других, но в современном приложении Spring вы обычно начинаете с контекста приложения, основанного на аннотациях.

Вам придется думать о методах внутри вашего класса конфигурации ApplicationContext как о фабричных методах. На данный момент есть один метод, который знает, как создавать экземпляры UserDao, и один метод, который создает экземпляры DataSource.

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

Но это приводит к вопросу: сколько экземпляров определенного компонента должно быть создано Spring?

Что такое Spring bean scope?

Сколько экземпляров наших DAO следует создать в Spring? Чтобы ответить на этот вопрос, вам нужно узнать о bean scope (область применения бина).

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

Аннотация области (scope annotation) определяет, сколько экземпляров создаст Spring. И, как упоминалось выше, это довольно просто:

Суть: большинство приложений Spring почти полностью состоят из одноэлементных bean-компонентов, в которые время от времени добавляются другие области действия bean-компонента (прототип, запрос, сессия, websocket и т.д.).

Теперь, когда вы знаете о ApplicationContexts, Beans & Scopes, давайте еще раз рассмотрим зависимости или то, как наш UserDAO может получить DataSource.

Что такое Spring Java Config?

До сих пор вы явно настраивали свои bean-компоненты в конфигурации ApplicationContext с помощью аннотированных @Bean методов Java.

Это то, что вы бы назвали Spring Java Config, в отличие от указания всего в XML, который исторически был подходом для Spring. Просто краткий обзор того, как это выглядит:

Это означает, что, если ваш MyApplicationContextConfiguration находится в пакете com.marcobehler, Spring будет сканировать каждый пакет, включая подпакеты, который начинается с com.marcobehler для поиска потенциальных компонентов Spring.

Читайте также:  Что такое честь мундира кратко

Давайте добавим аннотацию @Component к вашему UserDAO.

Теперь Spring имеет всю информацию, необходимую для создания bean-компонентов UserDAO:

Внедрение зависимости через конструктор и Autowired

В более новых версиях Spring действительно достаточно умен, чтобы внедрять эти зависимости без явной аннотации @Autowired в конструкторе. Так что это также будет работать.

Почему я упомянул @Autowired тогда? Поскольку это не повредит, то есть делает вещи более явными и потому что вы можете использовать @Autowired во многих других местах, кроме конструкторов.

Давайте рассмотрим различные способы внедрения зависимостей — внедрение конструкторов — всего лишь один из них.

Что такое Field Injection? Что такое Setter Injection?

Проще говоря, Spring не должен использовать конструктор для внедрения зависимостей.

Он также может напрямую внедрять поля.

Кроме того, Spring также может внедрять сеттеры.

Эти два стиля внедрения (поля, сеттеры) имеют тот же результат, что и внедрение конструктора: вы получите работающий Spring Bean. На самом деле есть еще один метод, называемый внедрением метода, который мы не будем здесь описывать.

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

Внедрение зависимости через конструктор или через поле

Было много споров в сети что лучше внедрение зависимости через конструктор или через поле и множеством громких голосов, утверждавших, что внедрение с помощью метода установки (setter) вредна.

Чтобы не добавлять шума к этим аргументам сформулируем суть этой статьи:

Резюме о контейнере Spring IoC

К настоящему моменту вы должны знать почти все, что вам нужно знать о контейнере зависимостей Spring.

Конечно, это еще не все, но если вы хорошо разбираетесь в ApplicationContexts, Beans, зависимостях и различных методах внедрения зависимостей, то вы уже на правильном пути.

Давайте посмотрим, что еще может предложить Spring, кроме инъекций чистой зависимости.

Spring AOP (Аспектно-ориентированное программирование) и прокси

Внедрение зависимостей поможет вести вас к более структурированным программам, но внедрение зависимости здесь и там не совсем то, в чем заключается суть экосистемы Spring. Давайте еще раз посмотрим на простую ApplicationContextConfiguration:

Вот где проявляется функция скрытая особенность Spring:

Однако Spring может обманывать и создавать что-то еще, кроме вашего класса UserService. Как? Почему?

Spring может создавать прокси

Потому что под капотом любой метод Spring @Bean может вернуть вам то, что (в вашем случае) выглядит и ощущается как UserService, но на самом деле это не так.

Он может вернуть вам прокси.

Прокси-сервер в какой-то момент делегирует службу UserService, которую вы написали, но сначала он выполнит свою собственную функциональность.

В частности, Spring по умолчанию создаст динамические прокси-серверы Cglib, которым не нужен интерфейс для работы прокси-серверов (например, внутренний механизм прокси-сервера JDK): вместо этого Cglib может прокси-классы посредством их подклассов на лету. (Если вы не уверены относительно отдельных шаблонов прокси, прочитайте больше о прокси в Википедии.)

Почему Spring желает создавать прокси?

Потому что это позволяет Spring дать вашим компонентам дополнительные функции без изменения кода. В сущности, это то, что является аспектно-ориентированным (или: AOP) программированием.

Spring аннотация @Transactional

Ваша реализация UserService выше может выглядеть примерно так:

Проблема: хотя Spring может создать ваш компонент UserService через конфигурацию applicationContext, он не может переписать ваш UserService. Он не может просто вставить туда код, который открывает соединение с базой данных и фиксирует транзакцию с базой данных.

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

Давайте еще раз посмотрим на эту безопасную ContextConfiguration.

Поначалу это может показаться немного не интуитивным, но большинство разработчиков Spring очень скоро сталкиваются с прокси в сеансах отладки. Из-за прокси трассировки стека Spring могут быть довольно длинными и незнакомыми: когда вы входите в метод, вы можете очень хорошо сначала войти в прокси — что отпугивает людей. Это, однако, совершенно нормальное и ожидаемое поведение.

Нужно ли Spring использовать прокси Cglib?

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

Также смотрите раздел: В чем разница между Spring AOP и AspectJ?

Резюме о поддержке Spring AOP

Управление ресурсами Spring

Мы уже давно говорим о внедрении зависимостей и прокси. Давайте теперь посмотрим на то, что я бы назвал важными утилитами удобства в среде Spring. Одной из таких утилит является поддержка ресурсов Spring.

Подумайте, как бы вы попытались получить доступ к файлу в Java через HTTP или FTP. Вы можете использовать класс URL в Java и написать некоторый код.

Точно так же, как бы вы читали в файлах из пути к классам вашего приложения? Или из контекста сервлета, это означает из корневого каталога веб-приложений (по общему признанию, это становится все реже и реже в современном приложении packaged.jar).

Опять же, вам нужно написать довольно много стандартного кода, чтобы он работал, и, к сожалению, код будет отличаться для каждого варианта использования (URL-адреса, пути к классам, контексты сервлетов).

Но есть решение: абстракция ресурсов Spring. Это легко объяснить в коде.

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

Как видите, он позволяет вам выполнять самые распространенные операции с ресурсом:

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

Абстракция ресурсов выглядит как такая крошечная функция, но она действительно сияет в сочетании со следующей удобной функцией, предлагаемой Spring: Properties.

Что такое Spring Environment?

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

Spring пытается упростить вам регистрацию и автоматический поиск свойств во всех этих различных источниках с помощью абстракции environment.

Что такое environment?

В двух словах, среда состоит из одного или многих источников свойств выполняемого Spring приложения. Например:

(Примечание. Среда также состоит из профилей, то есть профилей «dev» или «production», но мы не будем вдаваться в подробности о профилях в этом пересмотре этого руководства).

По умолчанию среда веб-приложения Spring MVC состоит из параметра ServletConfig/Context, источников системных свойств JNDI и JVM. Они также являются иерархическими, это означает, что они имеют порядок важности и перекрывают друг друга.

Тем не менее, довольно легко определить новые @PropertySources самостоятельно:

Теперь стало намного понятнее, почему мы говорили об управлении ресурсами Spring раньше. Потому что обе функции идут рука об руку.

Аннотация @PropertySource работает с любым допустимым классом конфигурации Spring и позволяет вам определять новые дополнительные источники с помощью абстракции ресурсов Spring: помните, что все дело в префиксах: http://, file://, classpath: и т.д.,

Определение свойств через @PropertySources — это хорошо, но разве нет лучшего способа, чем пройти через среду, чтобы получить к ним доступ? Да, есть.

Spring аннотация @Value и внедрение значений свойств

Spring Web MVC

Spring Web MVC, также известный как Spring MVC, является веб-средой Spring. Это позволяет создавать все, что связано с сетью, от небольших веб-сайтов до сложных веб-сервисов. Он также поддерживает фреймворки, такие как Spring Boot.

Что такое MVC?

Если вы совершенно не знакомы с MVC, вы можете прочитать страницу Model-View-Controller в Википедии, прежде чем продолжить чтение.

В контексте рендеринга HTML-страниц, скажем, страницы учетной записи пользователя, вот как выглядит MVC в Spring:

Итак, вашей конечной целью является написание контроллеров с помощью Spring, которые сопоставляются с конкретными HTTP-запросами, такими как (/account), и предоставляют пользователю соответствующую HTML-страницу, которая визуализируется путем объединения представления и данных, необходимых для этой страницы.

Та же логика верна для написания веб-сервисов JSON или XML.

Прежде чем мы рассмотрим реализацию класса типа контроллер, давайте сделаем шаг назад и посмотрим, как мы реализовали бы веб-страницу в низко-низко-низкоуровневом Java: с помощью старого доброго API сервлета Java (на котором основывается Spring MVC). ).

HttpServlet памятка

На данный момент игнорируем MVC: чтобы написать что-нибудь, связанное с HTTP с Java, вы бы использовали сервлеты или, в частности, HttpServlets (примечание для придир: да, есть и другие способы, спасибо за замечание). Сервлеты могут обрабатывать HTTP-запросы, а также возвращать браузеру или клиенту соответствующий HTTP-ответ.

После написания вашего сервлета вы должны зарегистрировать его в контейнере сервлетов, таком как Tomcat или Jetty. Регистрация сервлета всегда включает путь, чтобы указать, за какие URL в вашем веб-приложении отвечает ваш сервлет. Давайте предположим путь «/*», поэтому каждый входящий HTTP-запрос к вашему приложению обрабатывается одним сервлетом.

Вот как может выглядеть этот сервлет:

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

Кроме того, вашему MyServlet (контроллеру) необходимо выполнить довольно много ручного HTTP-специфического подключения, проверки URI запроса, просмотра строк, преобразования requestParameters и ответов и так далее.

Было бы намного приятнее, если бы вам не пришлось заботиться обо всем этом слесарном деле и позволить Spring сделать это за вас. Вот тут и приходит DispatcherServlet.

Что делает DispatcherServlet?

Uber-контроллер в среде Spring MVC Spring представляет собой сервлет, который называется DispatcherServlet.

Он называется DispatcherServlet, потому что он может буквально обрабатывать любой входящий HTTP-запрос, анализировать его содержимое и пересылать данные в виде симпатичных маленьких объектов Java в класс Controller.

Он также достаточно умен, чтобы брать выходные данные с этих контроллеров и конвертировать их в HTML / JSON / XML, в зависимости от того, что подходит. Весь процесс выглядит следующим образом (с пренебрежением большим количеством промежуточных классов, потому что DispatcherServlet не выполняет всю работу сам).

Это именно то, что вы хотите.

Давайте посмотрим на эти классы типа Controller более подробно.

Как писать классы типа Controller

Наконец, мы можем написать наш Controller класс, который обрабатывает запросы /account.

Страница /account будет HTML-страницей с несколькими динамическими переменными, такими как имя пользователя, адрес, информация о подписке и т.д.

В этих двух строчках происходит МНОГО, давайте посмотрим, что именно.

Наш метод Java возвращает строку с именем account. На самом деле это не просто строка, а ссылка на представление (HTML-шаблон). Давайте посмотрим на эти шаблоны на секунду.

Как генерировать HTML представление (view) с помощью Spring Web MVC

Spring MVC по умолчанию предполагает, что вы хотите визуализировать некоторый HTML. И, конечно же, вы не хотите сами отображать HTML-строки с помощью конкатенации строк, скорее вы захотите использовать шаблонную среду, такую как Velocity или Freemarker. Spring интегрируется со всеми этими технологиями.

Итак, вы могли бы иметь следующее представление (шаблон):
classpath:/templates/account.vm

Вот и все, разработка Spring MVC полностью завершена!

Как генерировать JSON / XML (представления) с помощью Spring Web MVC

С веб-сервисами вы не генерируете HTML, а генерируете XML или JSON. Это довольно просто, с Spring MVC также.

Конечно, вам нужна соответствующая библиотека, такая как Jackson, добавленная в ваш проект, но тогда вы можете просто аннотировать свой Controller дополнительной аннотацией, чтобы сигнализировать Spring: пожалуйста, преобразуйте мои объекты Java напрямую в XML / JSON, вместо того, чтобы я давал вам ссылка на вид.

Читайте также:  какая боль при тренировочных схватках

Но как Spring узнает, должен ли он возвращать XML, JSON или что-то еще?

Как работает согласование контента (content negotiation) Spring MVC

Существует множество способов, с помощью которых вы, как клиент, можете указать Spring MVC, какой формат ответа вы хотите при выполнении запроса к приложению Spring MVC.

Если вы хотите узнать больше о согласовании контента, ознакомьтесь с официальной документацией.

Какой тип ввода HTTP-запроса понимает Spring?

Spring MVC понимает в основном все, что предлагает HTTP — с помощью сторонних библиотек.

Это означает, что вы можете выбросить в него тела запросов JSON, XML или HTTP (Multipart) Fileupload, и Spring удобно преобразует этот ввод в объекты Java.

Какие HTTP-ответы может написать Spring MVC?

Spring MVC может записывать все что угодно в HttpServletResponse — с помощью сторонних библиотек.

Будь то HTML, JSON, XML или даже тела ответов WebSocket. Более того, он берет ваши объекты Java и генерирует эти тела ответов для вас.

А как насчет других концепций Spring MVC?

Официальная документация Spring MVC буквально содержит сотни страниц, описывающих, как работает веб-фреймворк.

Поэтому, если вы хотите узнать больше о RequestParams, Моделях, Представлениях, ViewHandlers, RootContexts, Фильтрах, Кэшировании и Безопасности, я приглашаю вас проверить это. Это просто не входит в рамки данного руководства, чтобы охватить все.

Однако в разделе часто задаваемых вопросов данного руководства есть ответы на несколько дополнительных вопросов.

Вы могли бы подумать, что она присуща Spring Boot (как я ошибочно делал слишком долго), но, как правильно заметил Мацей Волковяк, это часть простого старого Spring MVC. Вот его источник:

Это верно, Spring MVC @RestController — это не что иное, как Spring MVC @Controller в сочетании с аннотацией Spring MVC @ResponseBody — хотя вы можете подумать, что это что-то связанное со Spring Boot.

Резюме: Spring MVC

Spring MVC — это старый добрый фреймворк MVC, который позволяет довольно легко писать HTML / JSON / XML веб-сайты или веб-сервисы. Он прекрасно интегрируется с контейнером внедрения зависимостей Spring, включая все его вспомогательные утилиты.

Вкратце: он позволяет вам сосредоточиться на написании Java-классов, вместо того, чтобы иметь дело с сланцевым кодом сервлета, то есть работать с Http-запросами и ответами, и дает вам хорошее разделение проблем между вашей моделью и представлениями.

Дополнительные модули Spring Framework

Мы рассмотрели контейнер IoC Spring, Spring Web MVC и несколько других небольших модулей Spring. Но есть еще много. Что они делают?

О чем дополнительные модули Spring Framework?

Spring Framework состоит из еще большего количества удобных утилит, чем вы видели до сих пор. Давайте назовем их модулями и не путайте эти модули с 20 другими проектами Spring на spring.io. Наоборот, все они являются частью рамочного проекта Spring.

Итак, о каком удобстве идет речь?

Вы должны понимать, что в основном все, что Spring предлагает в этих модулях, также доступно на чистой Java. Предлагается либо JDK, либо сторонней библиотекой. Spring Framework всегда опирается на эти существующие функции.

Вот пример: отправка вложений электронной почты с помощью Java API Почты, безусловно, выполнима, но немного неудобна в использовании. Смотрите здесь примера кода.

Spring предоставляет приятную маленькую API-оболочку поверх Java Mail API, с тем дополнительным преимуществом, что все, что он предлагает, прекрасно вписывается в контейнер внедрения зависимостей Spring.

Итак, подытоживая, цель Spring Framework состоит в том, чтобы «упростить» доступную функциональность Java, подготовить ее к внедрению зависимостей и, следовательно, упростить использование API в контексте Spring.

Есть ли список всех дополнительных модулей Spring Framework?

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

Spring Framework: FAQ

Какую версию Spring я должен использовать?

Выбор версии Spring относительно прост:

В реальности вы можете найти проекты на Spring версии 4.x-5.x, используемые компаниями, хотя имеются и редкие, унаследованные проекты на Spring 3.x (первоначальный выпуск: 2009).

Как часто выпускаются новые версии Spring? Как долго они поддерживаются?

Вот хороший маленький график, показывающий историю версий Spring:

Вы можете видеть, что первоначальная версия Spring была

17 лет назад, а основные версии платформы выпускались каждые 3-4 года. Это не учитывает филиалы обслуживания, как бы то ни было.

Примечание. Текущий EOL() (больше никаких обновлений и поддержки) для всех версий Spring, кроме 5.2, в настоящее время настроен на 31 декабря 2020 года.

Какие библиотеки вам нужны, чтобы начать работу с Spring?

На самом деле существует только одна зависимость, которая вам нужна, когда вы хотите настроить проект Spring. Это называется spring-context. Это абсолютный минимум, чтобы заставить работать инъекционный контейнер Spring.

Для дополнительных функций Spring (таких как поддержка Spring JDBC или JMS) вам потребуются другие дополнительные библиотеки.

Вы можете найти список всех доступных модулей в официальной документации Spring, хотя с точки зрения зависимостей Maven artifactIds действительно следуют за именем модуля. Вот пример:

Чем отличаются версии Spring?

Подобно JVM, версии Spring безумно обратно совместимы, что означает, что вы можете (по существу) по-прежнему запускать файлы Spring 1.0 xml с последней версией Spring 5.0 (хотя я, по общему признанию, еще не пробовал это). Кроме того, обновление с, скажем, 3 до 5 также возможно с небольшими усилиями (см. Это руководство по миграции).

Таким образом, в целом, новые версии Spring основаны на более старых версиях Spring и имеют минимальные критические изменения (по сравнению, скажем, с Python 2 против 3). Итак, все основные концепции, которые вы изучили для Spring версии 3 или 4, остаются верными для Spring версии 5.

Вы можете получить отличный обзор того, что изменилось за последние 7 лет в отдельных версиях Spring, здесь:

Чтобы дать вам резюме:

Ядро (внедрение зависимостей, управление транзакциями и т.д.) Всегда остается неизменным или расширяется. Однако Spring идет в ногу со временем и предлагает поддержку для новых версий языка Java, улучшений инфраструктуры тестирования, веб-сокетов, реактивного программирования и т.д.

Что сейчас происходит в 20 других проектах Spring.io? Как насчет изменения реального байт-кода?

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

Вывод: все эти библиотеки расширяют Spring Framework и основываются на его основных принципах внедрения зависимостей.

В чем разница между Spring и Spring Boot?

Если вы прочитали это руководство, вы должны понимать, что Spring Boot построен поверх Spring. Несмотря на то, что скоро появится подробное руководство по Spring Boot, вот пример того, что означают «самоуверенные значения по умолчанию» в Spring Boot.

Проблема в том, что вы должны сами написать и настроить все эти отдельные части. Spring Boot, с другой стороны, берет эти отдельные части и связывает их вместе. Пример:

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

В чем разница между Spring AOP и AspectJ?

Как упомянуто выше в разделе Нужно ли Spring использовать прокси Cglib?» в Spring по умолчанию используется AOP на основе прокси. Он оборачивает ваши компоненты в прокси для достижения таких вещей, как управление транзакциями. Это имеет несколько ограничений и предостережений, но является довольно простым и понятным способом реализации наиболее распространенных проблем AOP, с которыми сталкиваются разработчики Spring.

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

Однако вы можете настроить Spring на использование AOP AspectJ вместо AOP по умолчанию на основе прокси.

Вот пара ссылок, если вы хотите получить больше информации по этой теме:

В чем разница между Spring и Spring Batch?

Spring Batch — это фреймворк, упрощающий написание пакетных заданий, т.е. «Читать эти 95 CSV-файлов каждую ночь в 3 часа ночи и вызывать внешнюю службу проверки для каждой записи».

Опять же, он построен на основе Spring Framework, но во многом является собственным проектом.

Тем не менее, обратите внимание, что по сути невозможно создать надежное пакетное задание без хорошего понимания общего управления транзакциями в Spring Framework и его отношения к Spring Batch.

В чем разница между Spring и Spring Web MVC?

Если вы прочитали это руководство, вы должны понимать, что Spring Web MVC является частью среды Spring.

Это могут быть RestControllers (где вы отправляете XML или JSON клиенту) или старые добрые HTML-контроллеры, где вы генерируете HTML с такими фреймворками, как Thymeleaf, Velocity или Freemarker.

В чем разница между Spring и Struts?

Вопрос должен быть: чем отличается Spring Web MVC от Struts?

Краткий исторический ответ таков: Spring Web MVC начинал как конкурент Struts, который, как утверждается, был плохо спроектирован разработчиками Spring (см. Википедию).

Современный ответ заключается в том, что, хотя Struts 2, безусловно, все еще используется в странном устаревшем проекте, Spring Web MVC является основой для всего, что связано с сетью во вселенной Spring. От Spring Webflow до RestControllers Spring Boot.

Что лучше? Spring XML или аннотации или Java конфигурация?

Spring начинался только с конфигурации XML. Затем медленно, все больше и больше появлялись аннотации / возможности Java конфигурации.

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

Обратите внимание на две вещи:

Что лучше? Внедрение зависимостей на основе конструктора или поля?

Как уже упоминалось в разделе о внедрении зависимостей, этот вопрос вызывает много разных мнений. Самое главное, что ваш выбор должен быть одинаковым для всего вашего проекта: не используйте внедрение на основе конструктора для 83% ваших бинов и внедрение на основе поля для остальных 17%.

Разумным подходом будет использование рекомендованного способа в документации Spring: использование внедрения конструктора для обязательных зависимостей, установка / установка поля для необязательных зависимостей, а затем проверка этих дополнительных зависимостей по всему классу на ноль.

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

Есть ли альтернативы контейнеру внедрения зависимостей в Spring?

Да, две популярные в экосистеме Java:

Обратите внимание, что Dagger предлагает только внедрение зависимостей, без дополнительных удобных функций. Guice предлагает внедрение зависимостей и другие функции, такие как управление транзакциями (с помощью Guice Persist).

Заключение

Если вы читали это далеко, то теперь у вас должно быть достаточно глубокое понимание того, что такое Spring Framework.

Вы узнаете, как это связано с другими библиотеками экосистемы Spring (такими как Spring Boot или Spring Data) в последующих руководствах, но сейчас я хочу, чтобы вы помнили эту метафору при попытке ответить на вопрос «Что такое Spring Фреймворк?»

Представьте, что вы хотите отремонтировать дом (

= создать программный проект).

Spring Framework — это ваш DIY-магазин (

= контейнер для инъекций зависимости), который предлагает множество различных инструментов, от горелок Бунзена (

= ресурсы / свойства) до кувалд (

= Web MVC) для вашего обновления. Эти инструменты просто помогут вам быстрее и удобнее отремонтировать ваш дом (создать приложение на Java).

(примечание: не спрашивайте меня, как я придумал эти сравнения;))

Вот и все на сегодня. Если у вас есть какие-либо вопросы или предложения, напишите мне по адресу marco@marcobehler.com или оставьте комментарий ниже. Для практических занятий ознакомьтесь с учебным курсом Spring Framework.

Спасибо за прочтение. Auf Wiedersehen.

Благодарности

(Благодарности автора оригинальной статьи — прим. перев.)

Источник

Сайт для любознательных читателей