bean java spring что это

Руководство по Spring. Введение в Bean-ы.

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

Бины – это объекты, которые являются основой приложения и управляются Spring IoC контейнером. Эти объекты создаются с помощью конфигурационных метаданных, которые указываются в контейнере (например, XML- … ). Я уже говорил о них в предыдущих главах.

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

В Spring Framework существуют такие свойства, определяющие бины:

class

Этот атрибут является обязательным и указывает конкретный класс Java-приложения, который будет использоваться для создания бина.

name

Уникальный идентификатор бина. В случае конфигурации с помощью xml-файла, вы можете использовать свойство “id” и/или “name” для идентификации бина.

scope

Это свойство определяет область видимости создаваемых объектов. (Прим. Отсутствие в русском языке достойного перевода этого свойства бинов могут вызвать затруднения, но более подробно оно будет рассмотрено далее).

constructor-arg

Определяет конструктор, использующийся для внедрения зависимости. Более подробно – далее.

properties

Определяет свойства внедрения зависимости. Более подробно рассмотрим далее.

initialization method

Здесь определяется метод инициализации бина

destruction method

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

autowiring mode

Определяет режим автоматического связывания при внедрении зависимости. Более подробно рассмотрим далее.

lazy-initialization mode

Режим ленивой инициализации даёт контейнеру IoC команду создавать экземпляр бина при первом запросе, а не при запуске приложения.

Контейнер IoC не зависит от формата, в котором передаются метаданные. Существует 3 основных метода передачи метаданных контейнеру Spring IoC:

Ранее мы уже рассматривали как передаются метаданные на основе XML-файла. Теперь давайте рассмотрим пример XML-файла с различными свойствами

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

Источник

Введение в Spring, или что делать, если по всему проекту @Autowired и @Component, а вы не понимаете, что это

Приветствую тебя, Хабр!

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

Начнем издалека. Существует такое понятие как Inversion of Control, по-русски – Инверсия управления, сокращенно – IoC. IoC — один из принципов, приближающий наш код к слабосвязанности. IoC — это делегирование части наших обязанностей внешнему компоненту.

Существуют разные реализации IoC подхода, нас интересует одна из них — Dependency Injection, внедрение зависимостей. Что это такое, название говорит само за себя, так что раскрыть ее я постараюсь на примере. Мы пишем приложение, автоматизирующее работу сети магазинов. Есть классы Shop (магазин) и Seller (продавец). У класса Seller имеется поле типа Shop — магазин, в котором работает продавец. Вот мы и столкнулись с зависимостью: Seller зависит от Shop. Теперь задумаемся, как в объект Seller попадет объект Shop? Есть варианты:

Перечисленные два способа — это реализация Dependency Injection (но пока еще это не IoC). И, наконец, мы подобрались к спрингу: он предоставляет еще один способ внедрять зависимости (а тут уже IoC).

Вообще говоря, Spring — это очень широкий набор библиотек на многие случаи жизни. Существует и Spring MVC для быстрого создания веб-приложений, и Spring Security для реализации авторизации в приложении, и Spring Data для работы с базами данных и еще куча всего. Но отдельно стоит Spring IoC — это базовый вид спринга, который реализует изучаемую нами тему — внедрение зависимостей. Spring IoC заслуживает внимания в самом начале изучения библиотек спринга по еще одной причине. Как вы увидите в процессе практической работы с другими видами спринга, для всех остальных спрингов Spring IoC используется как каркас.

Знакомство со Spring IoC начнем с главного термина: бин (англ. — bean). Самыми простыми словами,

Бин — создаваемый Spring-ом объект класса, который можно внедрить в качестве значения поля в другой объект.

Бин — объект класса, представляющий собой завершенный программный элемент с определенной бизнес-функцией либо внутренней функцией Spring’а, жизненным циклом которого управляет контейнер бинов.

Как вы уже поняли, для того, чтобы в Seller можно было внедрить Shop, Shop должен стать бином. Существует несколько способов рассказать приложению, какие объекты имеют гордое право называться бинами, все они приводят нас к понятию ApplicationContext. ApplicationContext — это сердце спринга. Как правило, он создается в самом начале работы приложения («поднимается») и управляет жизненным циклом бинов. Поэтому его еще называют контейнером бинов.

Подбираемся к главному. Каким образом нам необходимо переписать наши классы, чтобы Spring IoC и его слуга ApplicationContext подставили значение поля Shop объекту Seller? Вот таким:

Просто? Куда уж проще! Элегантно? Вполне. Здесь произошло следующее: аннотация Component сказала спрингу, что класс, который ей аннотируем, это бин. Аннотация Autowired попросила Spring в поле, которое она аннотирует, подставить значение. Эта операция называется «инжектнуть» (inject). Какое именно значение будет подставлено? Об этом чуть позже, сначала разберемся, как вообще классы становятся бинами.

Мы уже знаем, что в начале работы приложения должен подняться хранитель всех бинов ApplicationContext. Он-то и создает сразу все бины. Почти все. Дело в том, что по умолчанию любой бин имеет внутриспринговое свойство scope в значении singleton. Внутриспринговое, так как синглтоном в прямом смысле слова он не является. Он является синглтоном для спринга: при поднятии контекста Spring создаст ровно один объект-бин из указанного класса. Если вы хотите изменить такое поведение — пожалуйста, Spring разрешает управлять временем создания бина и их количеством для одного класса, но сейчас не об этом.

Читайте также:  flax meal что это

Итак, при поднятии ApplicationContext создаются все бины. Давайте выясним, а собственно где живет контекст и самое главное: как он определяет, из каких классов необходимо создавать бины. Вариантов несколько, для простоты изложения мы поговорим про один из них: конфигурирование с помощью файла xml. Вот его пример:

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

Второй путь менее многословен. Помните, над классами мы поставили аннотацию Component. Из всех классов, аннотированных этой аннотацией, будут созданы бины. Благодаря этой строке из xml-файла:

Она говорит спрингу: просканируй весь пакет main и из всего, над чем будет стоять аннотация Component (или другие аннотации, являющиеся наследниками Component), создай бины. Компактно, не правда ли? Просто говорим, в каких пакетах содержатся классы, из которых нужно создавать бины, и аннотируем эти классы.

Поднять контекст с использованием xml-файла можно следующей строчкой кода:

где beans.xml — путь к xml-нику, о котором шла речь выше.

С созданием бинов разобрались. Каким же образом Spring заполнит поле Shop при создании Seller’а? При поднятии контекста создается бин-объект класса Shop. Также создается бин-объект класса Seller, он же тоже аннотирован Component. У него есть поле типа Shop, аннотированное Autowired. Аннотация Autowired говорит спрингу: в это поле нужно инжектнуть бин. В нашем случае у нас есть всего один бин, подходящий на эту роль, то есть тип которого совпадает с типом поля: это бин — экземпляр класса Shop. Он и будет проинжектен в объект Seller, что и требовалось. Я понимаю, сейчас вопросики полезли как червячки: а что будет, если Spring не найдет нужный бин, или найдет несколько подходящих (особенно учитывая, что инжектить можно также по интерфейсу, а не по классу). Spring умен, но требует того же и от нас. Нам нужно либо иметь в системе ровно один бин, подходящий под каждый Autowired, либо обучать Spring действиям при таких конфликтах (об этом мы сейчас не будем, вы и так устали, крепитесь, статья подходит к концу).

Заметьте, что Seller – это тоже бин. Если бы он был не бином, а создавался через new, то автоматически бы ничего в него не проинжектнулось.

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

Возможно вы сейчас думаете, как красиво, просто и лаконично Spring позволяет внедрять зависимости. Но представьте, что что-то пошло не так и вам необходимо дебажить приложение. И все становится уже не так просто…

Парочка хинтов напоследок:

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

UPD (20.04.2021). Dependency Injection это не всегда IoC! В самом начале я как раз привожу примеры Dependency Injection, не являющиеся IoC.

Источник

Подготовка к Spring Professional Certification. Контейнер, IoC, бины

Доброго времени суток, Хабр.

Сегодня я решил представить вам перевод цикла статей для подготовки к Spring Professional Certification.

Это перевод только первой статьи, если он зайдет аудитории, я продолжу выпуск переводов.

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

В Spring Framework интерфейс org.springframework.factory.BeanFactory предоставляет фабрику для бинов, которая в то же время является IoC контейнером приложения. Управление бинами основано на конфигурации(java или xml).

Интерфейс org.springframework.context.ApplicationContext — это обертка над bean factory, предоставляющая некоторые дополнительные возможности, например AOP, транзакции, безопасность, i18n, и т.п.

Основа Spring Framework — контейнер, и наши объекты «живут» в этом контейнере.
Контейнер обычно создает множество объектов на основе их конфигураций и управляет их жизненным циклом от создания объекта до уничтожения.

Контейнер — это объект, реализующий интерфейс ApplicationContext.

Spring обеспечивает несколько разновидностей контекста.

Есть несколько основных реализаций интерфейса ApplicationContext:

Примеры создания контекста:

Если вы используете JUnit 5, то вам нужно указать 2 аннотации:

Если это не веб-приложение, то есть 2 способа:

В Spring Boot приложении:

Этот класс поместит в контейнер экземпляр класса DataSource. Позднее его можно будет использовать при доступе к базе данных.

Component scanning(сканирование компонентов) — Spring автоматически обнаруживает бины, которые будут находиться в контейнере. Это бины с аннотациями-стереотипами.

Component Корневая аннотация, которая помечает класс как кандидат для автовнедрения
Controller Указывает, что класс является контроллером для отправления данных на фронт.
@RestController Указывает, что класс является контроллером для REST.
Содержит аннотации Controller и @ResponseBody
Service Указывает, что класс является сервисом для выполнения бизнес-логики
Repository Указывает, что класс является репозиторием для работы с бд
@Configuration Указывает, что класс содержит Java-конфигурацию(@Bean-методы)

Область видимости — scope, скоуп. Существует 2 области видимости по умолчанию.

Читайте также:  с какими продуктами не сочетается цинк
Singleton Область видимости по умолчанию. В контейнере находится всего 1 экземпляр бина
Prototype В контейнере может находится любое количество экземпляров бина

И 4 области видимости в веб-приложении.

Request Область видимости — 1 HTTP запрос. На каждый запрос создается новый бин
Session Область видимости — 1 сессия. На каждую сессию создается новый бин
Application Область видимости — жизненный цикл ServletContext
WebSocket Область видимости — жизненный цикл WebSocket

Область видимости указывается с помощью аннотации @Scope на @Bean методах.

Prototype Scope не потокбезопасный, т.к. он не гарантирует что один и тот же экземпляр будет вызываться только в 1 потоке.

Singleton Scope же наоборот потокобезопасный.

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

Singleton bean можно внедрять в любой другой бин.

Prototype может быть зависимостью для любого бина.
Внедрять можно только singleton или prototype.

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

Есть 3 варианта для создания таких методов:

Ниже перечислены типы DI, которые могут быть использованы в вашем приложении:

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

Контейнер обрабатывает DI с помощью AutowiredAnnotationBeanPostProcessor. В связи с этим, аннотация не может быть использована ни в одном BeanFactoryPP или BeanPP.

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

Вы можете использовать разные типы внедрения:

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

Если в контейнере есть несколько бинов одного типа(SomeClass), то контейнер внедрит именно тот бин, над @Bean-методом которого стоит соответствующий квалификатор. Также можно не ставить квалификатор на метод, а использовать имя бина в качестве параметра квалификатора.
Имя бина можно можно указать через параметр аннотации Bean, а по умолчанию это имя фабричного метода.

Прокси это специальный объект, который имеет такие же публичные методы как и бин, но у которого есть дополнительная функциональность.
Два вида прокси:

Если в контейнере нет экземпляра бина, то вызывается @Bean-метод. Если экземпляр бина есть, то возвращается уже созданный бин.

В эту переменную будет внедрена строка, например из property или из view.

Как обычно, просьба присылать правки или найденные ошибки в личку.

Источник

Обратная сторона Spring

Неделя Spring на Хабре, судя по всему, открыта. Хочется сказать спасибо переводчику и комментаторам статьи «Почему я ненавижу Spring», которая не смотря на сильный негативный посыл в названии вызвала ряд интересных дискуссий, а так же тем, кто отреагировал на мою прошлую статью Как писать на Spring в 2017. Во многом благодаря комментариям к прошлой статье и появилась эта.

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

В комментариях к предыдущей статье несколько человек очень справедливо указали, что пример Hello World-а на Spring все же не очень показателен. Spring, особенно с использованием Spring Boot, дает ощущение простоты и всемогущества, но непонимание основ и внутренностей фреймворка ведет к большой опасности получить стектрейсом по логу. Что ж, чтобы немного развеять ощущение полной магии происходящего, сегодня мы возьмем приложение из предыдущей статьи и разберем, как и что происходит внутри фреймворка и от каких проблем нас отгораживает Boot. Целевая аудитория все же начинающие разработчики, но с некоторым опытом и базовыми знаниями Java и Spring. Хотя, возможно, и опытным пользователям Spring будет интересно освежить знания того, что происходит под капотом.

Ключевые понятия

Начнем срывать покровы с самых базовых понятий Spring. Бин (bean) — это не что иное, как самый обычный объект. Разница лишь в том, что бинами принято называть те объекты, которые управляются Spring-ом и живут внутри его DI-контейнера. Бином является почти все в Spring — сервисы, контроллеры, репозитории, по сути все приложение состоит из набора бинов. Их можно регистрировать, получать в качестве зависимостей, проксировать, мокать и т.п.

DI контейнер

Ключевой и фундаментальный механизм Spring. Внешне очень простой, но внутри он предоставляет очень много механизмов для тонкой настройки зависимостей. По сути, любое приложение Спринг — это набор бинов, связанных вместе через DI контейнер.

Еще один очень важный момент, который многие упускают при обсуждении DI контейнера, это то, что использование инъекции зависимостей не подразумевает создания интерфейсов для каждого компонента. Это очень простая мысль, но я много раз видел, что из-за своей простоты она не всегда очевидна. Более того, создание интерфейса, если у него лишь одна реализация — считается плохой практикой. Т.е. классы вполне могут сами по себе быть объектами DI. Более того, отсутствие интерфейса даже не мешает их мокать в тестах, т.к. Mockito, например, вполне умеет мокать классы.

Контекст

Конфигурация

Итак, если приложение — это набор бинов, чтобы оно заработало нам нужно этот набор описать.

Конфигурация — это просто описание доступных бинов. Spring дает несколько вариантов, как можно описать набор бинов, которые сформируют приложение. Исторический вариант — это через набор xml файлов. В наши дни ему на смену пришли Java аннотации. Spring Boot построен на аннтациях чуть более, чем полностью и большинство современных библиотек в принципе тоже можно сконфигурить через аннотации. В третьем своем поколении, конфигурация бинов пришла к подходу функциональной регистрации (functional bean registration), которая станет одной из важных новых фич готовящегося к выходу Spring 5.

Читайте также:  какой индекс уф опасен для человека

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

Эта конфигурация определяет два бина, причем второй зависит от первого. И здесь в игру вступит Spring – когда мы просим предоставить инстанс PaymentProvider — Spring найдет его в контексте и предоставит нам.

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

Сканирование компонентов

Резюме

Spring Boot

Теперь переходим к следующей части. Допустим, нам надо сконфигурить подключение к MySQL базе данных. Если мы хотим использовать Spring Data JPA с Hibernate в качестве провайдера, нам потребуется сконфигурировать несколько бинов — EntityManagerFactory (основной класс JPA), DataSource для подключения непосредственно к базе через JDBC драйвер и т.п. Но с другой стороны, если мы это делаем каждый раз и, по сути, делаем одно и то же — почему бы это не автоматизировать? Скажем, если мы указали строку подключения к базе и добавили зависимость на MySQL драйвер — почему бы чему-то автоматически не создать все нужные бины для работы с MySQL? Именно это и делает Spring Boot. По сути, Spring Boot это просто набор классов конфигурации, которые создают нужные бины в контексте. Точно так же их можно создать руками, просто Boot это автоматизирует.

Автоконфигурация

Важное понятие Spring Boot это автоконфигурация. По сути, это просто набор конфигурационных классов, которые создают и регистрируют определенные бины в приложении. По большому счету, даже сам Embedded Servlet Container — это просто еще один бин, который можно сконфигурировать! Пара важных моментов, которые важно знать об автоконфигурации:

Условия и порядок регистрации бинов

Логика при регистрации бинов управляется набором @ConditionalOn* аннотаций. Можно указать, чтобы бин создавался при наличии класса в classpath ( @ConditionalOnClass ), наличии существующего бина ( @ConditionalOnBean ), отсуствии бина ( @ConditionalOnMissingBean ) и т.п.

Spring Boot активно использует эти аннотации чтобы оставаться как можно более незаметным и не перекрывать пользовательские конфигурации.

Погружение в Hello World

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

Итак, наше приложение включает такой код:

Давайте разберем что здесь происходит по шагам.

Класс DemoApplication

Т.е. наличие @SpringBootApplication включает сканирование компонентов, автоконфигурацию и показывает разным компонентам Spring (например, интеграционным тестам), что это Spring Boot приложение

SpringApplication.run()

То получим точно такое же работающее приложение, т.к. класс AnnotationConfigEmbeddedWebApplicationContext найдет в контексте бин типа EmbeddedServletContainerFactory и через него создаст и запустит встроенный контейнер. Обратите внимание, что все это работает в рамках общего DI контейнера, то есть этот класс можно реализовать самим.

@EnableAutoConfiguration

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

Т.е. это самый обычный импорт конфигурации, про который мы говорили выше. Класс же EnableAutoConfigurationImportSelector (и его преемник в Spring Boot 1.5+ — AutoConfigurationImportSelector ) это просто конфигурация, которая добавит несколько бинов в контекст. Однако, у этого класса есть одна тонкость — он не объявляет бины сам, а использует так называемые фабрики.

Класс EnableAutoConfigurationImportSelector смотрит в файл spring.factories и загружает оттуда список значений, которые являются именами классов (авто)конфигураций, которые Spring Boot импортирует.

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

По сути, ее можно заменить на ручной импорт нужных конфигураций:

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

«Но это же медленно!». И да, и нет — под рукой нет точных цифр, но сам по себе процесс автоконфигурации очень быстрый (порядка сотни миллисекунд на абстрактной машине в вакууме)

Краткое резюме

В основе «магии» Spring Boot нет ничего магического, он использует совершенно базовые понятия из Spring Framework. В кратком виде процесс можно описать так:

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

Диагностика

Auto-configuration report

В ответ Spring выдаст детальный Auto-configuration report:

Строчка в Positive / Negative matches будет для каждой примененной автоконфигурации, более того, Boot сообщит, почему тот или иной бин был создан (т.е. укажет, какие из условий регистрации были выполнены).

Actuator

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

Резюме

Spring все же остается большим и не самым простым фреймворком, но это цена высокоуровневых абстракций, которые он предоставляет. И хотя знать все тонкости работы фреймворка в ежедневной разработке не нужно, знать, как он работает изнутри, все же, полезно. Надеюсь, что эта статья помогла понять важность и ценность Spring именно как экосистемы и убрала немного «магичности» в происходящем, особенно при использовании Spring Boot. Мой совет — не бойтесь углубляться в недра фреймворка, читайте исходники и документацию, благо они у Spring-a почти эталонные, на мой взгляд.

Источник

Сказочный портал