SPRING Flashcards
Что такое Spring Framework и какие основные задачи он решает?
Spring Framework - это фреймворк для разработки приложений на языке Java, который предоставляет комплексное решение для различных задач, связанных с разработкой приложений.
Основная идея заключается в том, что Spring берет на себя ответственность за создание объектов и управление ими, вместо того, чтобы доверять это процессу создания объектов в языке Java.
В рамках механизма управления жизненным циклом объектов Spring осуществляет инъекцию зависимостей, конфигурирование бинов (англ. bean configuration), управление состоянием и жизненным циклом бинов (Жизненный цикл объекта состоит из нескольких этапов, включая создание, инициализацию, использование и уничтожение.).
Основные задачи, которые решает Spring Framework, включают в себя:
- Управление жизненным циклом объектов: Spring позволяет контролировать жизненный цикл объектов приложения, в том числе создание, настройку и уничтожение объектов.
- Внедрение зависимостей: Spring предоставляет механизм внедрения зависимостей, который позволяет автоматически связывать объекты в приложении. Это уменьшает связность между объектами и повышает гибкость приложения.
- Транзакции: Spring предоставляет механизм управления транзакциями, который позволяет создавать и управлять транзакциями при работе с базами данных и другими ресурсами.
- Безопасность: Spring предоставляет механизмы для реализации безопасности приложений, включая аутентификацию, авторизацию, защиту от атак и другие меры.
- Работа с базами данных: Spring предоставляет удобные средства для работы с базами данных, включая JDBC и ORM-фреймворки, такие как Hibernate и JPA.
- Веб-разработка: Spring предоставляет механизмы для разработки веб-приложений, включая поддержку MVC-архитектуры, обработку запросов и создание RESTful API.
- Тестирование: Spring упрощает тестирование приложений, предоставляя механизмы для создания тестовых контекстов и поддержку интеграционного тестирования.
Таким образом, Spring Framework предоставляет комплексное решение для различных задач, связанных с разработкой приложений на языке Java, и позволяет ускорить процесс разработки, повысить качество кода и облегчить поддержку приложения.
Как происходит конфигурирование Spring?
Конфигурирование Spring происходит через специальный файл конфигурации, который может быть в формате XML, Java-кода или аннотаций. В этом файле описываются бины (классы, объекты или компоненты), которые необходимы для работы приложения, и их свойства.
Существует несколько способов конфигурирования Spring:
- XML-конфигурация: в этом способе конфигурации все настройки приложения описываются в XML-файле, который загружается при запуске приложения. Примером такого файла может быть applicationContext.xml.
- Java-конфигурация: в этом способе конфигурации настройки приложения описываются в виде Java-кода. Этот способ использует аннотации, такие как @Configuration, @Bean, @ComponentScan и др., и может быть предпочтительнее, если требуется более гибкая настройка.
- Конфигурация на основе аннотаций: в этом способе конфигурации все настройки приложения описываются в аннотациях, которые применяются к классам, методам и полям. Этот способ использует аннотации, такие как @Component, @Autowired, @Value и др., и может быть предпочтительнее, если требуется более компактный и читаемый код.
После того, как файл конфигурации был создан, его необходимо загрузить в Spring контейнер при запуске приложения. Это делается с помощью специального класса ApplicationContext, который загружает конфигурацию и создает бины. Затем приложение может использовать эти бины для выполнения своей работы.
Spring также предоставляет механизмы для автоматической конфигурации, которые могут сэкономить время и упростить настройку. Например, Spring Boot предоставляет автоматическую конфигурацию для большинства приложений, которая может быть настроена с помощью специальных файлов настроек и аннотаций.
Что такое инверсия контроля (IoC) и внедрение зависимостей (DI)? Как эти принципы реализованы в Spring?
Inversion of Control –это принцип в разработке программного обеспечения, при котором управление объектами или частями программы передается контейнеру или фреймворку.принцип для написания слабосвязанного кода
Dependencies -другие объекты (как правило других классов), с которыми работает и чью функциональность использует текущий объект.
Dependency Injection является способом реализации принципа IoC в Spring через рефлексию:
DI механизм передачи классу его зависимостей
Dependency Injection (DI) - это механизм внедрения зависимостей, при котором классы не создают свои зависимости, а получают их из внешних источников, таких как Spring-контейнер.
DI механизм позволяет классам работать со своими зависимостями, не заботясь о том, как они создаются и управляются. Вместо этого класс принимает зависимости через конструктор, методы или поля, которые автоматически заполняются при создании объекта.
Spring определяет и внедряет зависимости через (на выбор):
* Конструкторы: можно помечать конструкторы аннотацией @Autowired, чтобы Spring автоматически искал подходящие бины для всех параметров конструктора и использовал их для создания экземпляра класса.
* Сеттеры: можно помечать методы-сеттеры аннотацией @Autowired, чтобы Spring автоматически внедрял бины в соответствующие поля.
* Поля: можно также помечать поля класса аннотацией @Autowired, чтобы Spring автоматически внедрял бины в эти поля.
* Методы-фабрики: можно пометить статический метод класса аннотацией @Bean, который возвращает экземпляр класса, чтобы Spring использовал этот метод в качестве фабричного метода для создания бинов.
В Spring Framework инверсия контроля достигается именно внедрением зависимостей. В Spring Framework инверсия контроля и внедрение зависимостей считаются одним и тем же.
IoC-контейнер отвечает за управление жизненным циклом объектов: создание, вызов методов инициализации и конфигурирование объектов через связывание их между собой.
Объекты, создаваемые контейнером, называются beans. Конфигурирование контейнера осуществляется через внедрение аннотаций, но есть возможность, по старинке, загрузить XML-файлы, содержащие определение bean’ов и предоставляющие информацию, необходимую для создания bean’ов.
IoC - аутсорсинг создания и управления объектами. Т.е. передача программистом прав на создание и управление объектами Спрингу
DI - аутсорсинг добавления/внедрения зависимостей. DI делает объекты нашего приложения слабо зависимыми друг от друга.
DI это частный случай IoC
IoC это принцип или методология, а DI это конкретная реализация
- IoC - (принцип, набор рекомендаций для написания слабосвязанного кода) Принцип
- DI - (один из способов реализовать принцип) Паттерн
- IoC - Container ( приложение, реализующее принцип) Фрэймворк
Что такое IoC контейнер?
IoC контейнер - это механизм, используемый в фреймворке Spring для управления жизненным циклом объектов, а также для внедрения зависимостей между объектами.
IoC Container - это объект, который занимается созданием других объектов и внедрением в них зависимостей(DI)
в IOC (Inversion of Control) контейнере объекты, или бины, хранятся в ассоциативном массиве, где ключом обычно является уникальный идентификатор (например, строковый), который позволяет получить доступ к соответствующему объекту. Это позволяет легко настраивать зависимости между бинами и обеспечивает централизованное управление созданием и конфигурированием объектов, что упрощает разработку приложений.
Контейнер Spring представляет собой реализацию принципа Inversion of Control (IoC), который состоит в том, что контроль за жизненным циклом объектов передается контейнеру, который управляет созданием, настройкой и уничтожением объектов.
В Spring Framework контейнер отвечает за создание, настройку и сборку объектов, известных как бины, а также за управление их жизненным циклом. Он (контейнер) представлен интерфейсом ApplicationContext.
Spring Framework предоставляет несколько реализаций интерфейса ApplicationContext:
* ClassPathXmlApplicationContext и FileSystemXmlApplicationContext - для автономныхприложений;
* WebApplicationContext - для веб-приложений;
* AnnotationConfigApplicationContext - для обычной Java-конфигурации, в качестве аргумента которому передается класс, либо список классов с аннотацией @Configuration, либо с любой другой аннотацией JSR-330, в том числе и @Component.
ApplicationContext может быть настроен разными способами:
* через XML-файлы,
* аннотации
* чистый Java-код.
Контейнер автоматически находит классы с аннотациями, такими как @Component, @Service и т.д., и создает объекты-бины на основе их определений. Кроме того, он позволяет внедрять зависимости между бинами с помощью аннотации @Autowired или XML-конфигурации.
Spring BeanFactory Container Это самый простой контейнер, который обеспечивает базовую поддержку DI и который основан на интерфейсе org.springframework.beans.factory.BeanFactory.
BeanFactory обычно используется тогда, когда ресурсы ограничены (мобильные устройства). Поэтому, если ресурсы не сильно ограничены, то лучше использовать ApplicationContext.
Spring ApplicationContext Container является более сложным и более продвинутым Spring Container-ом. Наследует BeanFactory и так же загружает бины, связывает их вместе и конфигурирует их определённым образом. Но кроме этого предоставляет дополнительные возможности, например AOP и транзакции. Этот контейнер определяется интерфейсом org.springframework.context.ApplicationContext.
Контейнер Spring может создавать объекты в различных скоупах, таких как Singleton, Prototype, Session и Request. Singleton обеспечивает создание единственного экземпляра объекта на уровне приложения, тогда как Prototype создает новый экземпляр каждый раз при запросе объекта. Session и Request используются в веб-приложениях и обеспечивают создание объектов на уровне сессии и запроса соответственно.
Контейнер Spring позволяет внедрять зависимости между объектами при помощи автоматического связывания (Autowiring) или явного задания зависимостей. Автоматическое связывание позволяет контейнеру Spring самостоятельно определить зависимости между объектами на основе их типа и имен, тогда как явное задание зависимостей использует аннотации, XML-конфигурацию или Java-код для определения зависимостей.
Что такое Bean в спринге?
Бин (bean) — это обычный объект. Разница лишь в том, что бинами принято называть те объекты, которые создаются и управляются IO-контейнером и живут внутри него.
@Bean - это объект со всеми необходымыми зависимостями, который был создан с помощью IoC Container
Еще можно добавить, что Bean это переиспользуемый програмный компонент
Bean Definition - это чертеж
Bean - это деталь, созданная по данному чертежу
Иначе говоря, бин — это просто один из множества объектов в вашем приложении. Бины и их зависимости отражаются в метаданных конфигурации, используемых контейнером.
По умолчанию бин задается как синглтон.
Таким образом все публичные переменные класса могут быть изменены одновременно из разных мест, а значит бин - не потокобезопасен. Однако поменяв область действия бина на request, prototype, session он станет потокобезопасным, но это скажется на производительности.
Существуют несколько требований к бину в Spring:
- Класс должен иметь конструктор без аргументов.
- Класс должен быть открытым (public).
- Класс должен быть не абстрактным (abstract).
- Класс должен содержать публичные методы, если они используются для внедрения зависимостей через сеттеры.
- Класс должен быть помечен одной из аннотаций: @Component, @Service, @Controller или другой аннотацией, которая явно указывает на то, что этот класс является Spring bean.
- Если используется XML-конфигурация, то класс должен быть определен в XML-файле.
- Если используется аннотационная конфигурация, то класс должен быть сканирован при помощи аннотации @ComponentScan.
- Если класс реализует интерфейс BeanNameAware, то он должен иметь метод setBeanName(), который будет вызываться при создании бина для передачи ему его имени в качестве аргумента.
- Если класс реализует интерфейс InitializingBean, то он должен иметь метод afterPropertiesSet(), который будет вызываться после внедрения всех зависимостей.
- Если класс имеет метод, помеченный аннотацией @PostConstruct, то этот метод будет вызван после внедрения зависимостей и перед тем, как бин будет доступен для использования.
- Если класс имеет метод, помеченный аннотацией @PreDestroy, то этот метод будет вызван перед уничтожением бина.
- Если класс реализует интерфейс DisposableBean, то он должен иметь метод destroy(), который будет вызываться перед уничтожением бина.
Расскажите про аннотацию @Bean?
Аннотация @Bean используется для указания того, что метод создает, настраивает и инициализирует новый объект, управляемый IoC-контейнером.
Как правило используется в классах с аннотацией @Configuration,
Может использоваться и в классах с аннотацией @Component (или ее наследниках).
Позволяет дополнительно определить у бина:
- name - имя (уникальный идентификатор) бина;
- initMethod - имя метода для вызова во время инициализации бина;
- destroyMethod - имя метода для вызова во время удаления бина из контекста;
- autowireCandidate - является ли этот бин кандидатом на автоматическое внедрение в другой бин.
@Configuration public class MyConfig { @Bean(name = "myBean", initMethod = "init", destroyMethod = "cleanup") @Scope("prototype") @DependsOn("dependencyBean") public MyBean myBean() { return new MyBean(); } @Bean(name = "dependencyBean") public DependencyBean dependencyBean() { return new DependencyBean(); } }
Что такое Bean definition и metadata?
Bean definition - это описание бина, которое может содержать информацию о классе бина, его свойствах, зависимостях и других метаданных. В Spring бины создаются и настраиваются в IoC контейнере, на основе Bean definition.
Bean definition может содержать информацию о классе объекта, его свойствах, зависимостях, и других конфигурационных параметрах.
@Configuration public class MyConfig { @Bean public MyBean myBean() { MyBean bean = new MyBean(); bean.setMyProperty("myValue"); return bean; } }
В этом примере метод myBean() является фабричным методом, который возвращает экземпляр класса MyBean. Аннотация @Bean указывает, что метод должен быть обработан IoC контейнером как Bean definition, и результат его выполнения должен быть помещен в контейнер.
Вот несколько примеров аннотаций, которые можно отнести к Bean Definition:
* @Bean - используется для объявления метода, который возвращает объект, который будет управляться контейнером Spring. Этот метод может содержать логику создания, настройки и инициализации бина.
* @Configuration - используется для указания, что класс содержит один или несколько методов, которые возвращают бины, которые нужно создать и настроить. Эта аннотация является альтернативой использованию XML-файлов конфигурации.
* @ComponentScan - указывает Spring-контейнеру, какие пакеты нужно сканировать, чтобы найти все классы, которые могут быть использованы как бины. Эта аннотация может использоваться в классах конфигурации.
* @Import - используется для импорта конфигурационных классов или Java-конфигураций в текущий контекст приложения.
* @Conditional - позволяет задать условия для создания бина. Бин будет создан только в том случае, если указанные условия выполняются.
* @Lazy - используется для указания, что бин должен быть создан только в момент, когда он первый раз используется.
Метаданные это дополнительная информация о бинах, которая может быть использована для настройки их создания и поведения.
Метаданные могут быть использованы для описания различных аспектов бина, таких как область видимости, жизненный цикл, зависимости, аспекты и т.д. Например, для управления областью видимости можно использовать аннотации, такие как @Scope, а для управления жизненным циклом - аннотации, такие как @PostConstruct и @PreDestroy.
@Component @Scope("prototype") public class MyBean { @Autowired private MyDependency dependency; // ... }
Вот несколько примеров аннотаций, которые можно отнести к метаданным:
* @Autowired - указывает на необходимость внедрения зависимости для данного бина. Аннотация может использоваться для полей, методов и конструкторов.
* @Qualifier - используется вместе с @Autowired для разрешения неоднозначности, когда в контейнере существует несколько бинов одного типа. Она позволяет указать конкретный бин, который должен быть внедрен.
* @Value - позволяет задать значение свойства бина в виде строки. Аннотация может использоваться для полей, методов и конструкторов.
* @PostConstruct - позволяет указать метод, который должен быть вызван после создания бина, но перед тем, как он будет использован. Это может быть полезно для инициализации объектов.
* @Scope - позволяет указать область видимости бина. По умолчанию, бины создаются в области видимости singleton, но можно использовать и другие области видимости, такие как prototype, request, session и другие.
* @Profile - позволяет определить профиль, которому соответствует данный бин. Бины с определенным профилем будут созданы только в том случае, если данный профиль активен.
Расскажите про аннотацию @Component?
Это аннотация Spring Framework, ею мы помечаем класс, если хотим, чтобы из этого класса был создан бин. Именно эту аннотацию ищет Spring Framework, когда сканирует наши классы. Можно указать имя (Id) для создаваемого бина, а можно не указывать, тогда по умолчанию именем будет название класса с маленькой буквы.
Когда класс помечается аннотацией @Component, Spring автоматически создает экземпляр этого класса в качестве бина в контейнере. Это позволяет другим классам в приложении использовать этот компонент через механизм внедрения зависимостей (DI).
Аннотация @Component имеет наследников: @Repository, @Service и @Controller. Все они являются частными случаями использования @Component для слоёв DAO, сервиса и контроллера MVC соответственно.
@Component - Spring определяет этот класс как кандидата для создания bean.
@Service - класс содержит бизнес-логику и вызывает методы на уровне хранилища. Ничем не отличается от классов с @Component.
@Repository - указывает, что класс является слоем, взаимодействующем с ДБ. Задача @Repository заключается в том, чтобы отлавливать исключения персистентности и приводить их к подклассам DataAccessExeption спринга.Для этого Spring оборачивает эти классы в прокси, и в контекст должен быть добавлен класс PersistenceExceptionTranslationPostProcessor.
@Controller - указывает, что класс выполняет роль контроллера MVC. DispatcherServlet просматривает такие классы для поиска @RequestMapping.
@RequestMapping используется для мапинга (связывания) с URL для всего класса или для конкретного метода обработчика.
@Configuration - означает, что класс будет содержать bean definition методы с аннотацией @Bean. Класс, помеченный этой аннотацией, должен быть открытым и не должен быть final. Конструкторы в таком классе должны быть public или protected, а методы, возвращающие bean, должны быть отмечены аннотацией @Bean.
@RequestMapping используется для мапинга (связывания) с URL для всего класса или для конкретного метода обработчика.
Чем отличаются аннотации @Bean и @Component?
Аннотация @Component (как и @Service и @Repository) используется для автоматического обнаружения и автоматической настройки бинов в ходе сканирования путей к классам.
@Component используется для аннотирования классов, которые должны быть автоматически обнаружены и зарегистрированы в контексте Spring. Эта аннотация может быть использована для любого компонента, такого как сервисы, репозитории, контроллеры и т.д.
@Bean используется для методов, которые должны быть вызваны для создания и инициализации объектов в контексте Spring. Эта аннотация может использоваться в классах, помеченных аннотацией @Configuration, и методы, помеченные этой аннотацией, будут вызываться для создания бинов.
Аннотация @Bean используется для явного объявления бина и позволяет добавить bean, уже реализованного сторонней библиотекой.
Аннотация @Bean используется для явного объявления бина, а не для того, чтобы Spring делал это автоматически в ходе сканирования путей к классам:
- прописываем вручную метод для создания бина;
- делает возможным объявление бина независимо от объявления класса, что позволяет использовать классы из сторонних библиотек, у которых мы не можем указать аннотацию @Component;
- с аннотацией @Bean можно настроить initMethod, destroyMethod, autowireCandidate, делая создание бина более гибким.
Таким образом, основное отличие между @Bean и @Component заключается в том, что первая используется для создания и настройки объектов в контексте Spring, а вторая для обнаружения и регистрации компонентов в контексте Spring.
Расскажите про аннотации @Service и @Repository. Чем они отличаются?
Аннотация @Service и @Repository являются специализированными версиями аннотации @Component в Spring Framework, и каждая из них предназначена для использования в конкретных слоях приложения.
Аннотация @Repository предназначена для классов, которые предоставляют доступ к базе данных или другим источникам данных, таким как файловые системы или JMS-очереди. Эта аннотация обычно используется в слое доступа к данным (DAO).
Задача @Repository заключается в том, чтобы отлавливать определенные исключения персистентности и пробрасывать их как одно непроверенное исключение Spring Framework. Для этого в контекст должен быть добавлен класс PersistenceExceptionTranslationPostProcessor.
Мы помечаем бины аннотацией @Service, чтобы указать, что они содержат бизнес- логику. Так что нет никакого другого предназначения, кроме как использовать ее на уровне сервиса.
Аннотация @Service предназначена для классов, которые предоставляют бизнес-логику приложения, такую как обработка данных и выполнение операций над ними. Эта аннотация обычно используется в сервисном слое приложения.
Расскажите про аннотацию @Autowired
Аннотация @Autowired в Spring Framework используется для автоматической внедрения зависимостей в поля классов, методы или конструкторы.
Она позволяет автоматически связывать бины (объекты) между собой,
Это означает, что Spring Framework автоматически находит классы, которые удовлетворяют зависимости, объявленные в вашем классе, и создает экземпляры этих классов, которые можно использовать.
Это аннотация Spring Framework, ею помечают конструктор, поле, сеттер-метод или метод конфигурации, сигнализируя, что им обязательно требуется внедрение зависимостей.
@Autowired – автоматическое внедрение подходящего бина:
- Спринг сканирует все классы, которые могут быть использованы в качестве бинов и создает эти бины на основе определенных аннотаций, таких как @Component, @Service, @Repository и т.д.
- При создании каждого бина, Spring анализирует его зависимости и пытается автоматически связать их во время запуска приложения. Это называется автосвязыванием (autowiring).
- Когда Spring встречает аннотацию @Autowired над полем, конструктором или методом, он ищет бины, которые могут удовлетворить тип или имена зависимостей, указанные в аннотации.
- Если Spring находит только один соответствующий бин, то он будет использован для автосвязывания.
- Если не найдено ни одного соответствующего бина, то Spring выбросит исключение, , если не указать @Autowired(required = false).
- Если найдено несколько соответствующих бинов, то Spring использует стратегию выбора подходящего бина на основе алгоритма приоритетов (по умолчанию используется приоритет типа бина, затем имя бина, затем значение аннотации @Primary, и т.д.). Если этот алгоритм не удается разрешить неоднозначность, то Spring выбросит исключение.
- Если необходимо, можно использовать дополнительные аннотации, такие как @Qualifier или @Primary, чтобы уточнить, какой бин должен быть использован для конкретной зависимости.
При циклической зависимости, когда объекты ссылаются друг на друга, нельзя ставить над конструктором.
Начиная со Spring Framework 4.3, аннотация @Autowired для конструктора больше не требуется, если целевой компонент определяет только один конструктор.
Мы также можем указать Spring предоставить все бины определенного типа из ApplicationContext, добавив аннотацию @Autowired в поле или метод с массивом или коллекцией этого типа:
~~~
@Autowired
public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) {
this.movieCatalogs = movieCatalogs; }
~~~</MovieCatalog>
Даже коллекции типа Map могут быть подключены автоматически, если тип ключа - String. Ключами будут имена бинов, а значениями - сами бины:
private Map<String, MovieCatalog> movieCatalogs; @Autowired public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs){ this.movieCatalogs = movieCatalogs; }
Основные правила использования аннотации @Autowired в Spring Framework:
Основные правила использования аннотации @Autowired в Spring Framework:
- Аннотация @Autowired может быть использована для инъекции зависимостей в полях класса, конструкторы, методы(сеттеры) и параметры методов.
- При использовании аннотации @Autowired для инъекции зависимостей в свойства класса, должен быть настроен bean с соответствующим типом.
- Если существует более одного подходящего bean-а для инъекции, необходимо использовать аннотацию @Qualifier для выбора конкретного bean-а.
- Если необходимо использовать аннотацию @Autowired для инъекции зависимостей в конструктор, метод или параметр метода, то должен быть определен только один подходящий bean.
- Если необходимо, чтобы инъекция зависимостей была необязательной, то можно добавить параметр required=false в аннотацию @Autowired.
- Аннотация @Autowired может быть использована как для автосвязывания по типу, так и для связывания по имени. Второй вариант возможен, если свойство, метод или конструктор имеет соответствующее имя, как у бина.
- Аннотация @Autowired также может быть использована для инъекции зависимостей, которые не являются бинами Spring Framework, таких как JDBC-DataSource или EntityManager.
- Аннотация @Autowired может быть использована в сочетании с аннотациями @Qualifier, @Primary, @Resource и @Value для более тонкой настройки инъекции зависимостей.
- Аннотация @Autowired может быть использована в сочетании с аннотациями @Transactional и @Scheduled для инъекции зависимостей, которые требуют управления транзакциями и планирования задач.
- Не рекомендуется использовать аннотацию @Autowired в классах, которые не управляются контейнером Spring Framework, таких как классы модели или службы. Вместо этого следует использовать конструкторы, методы и свойства для внедрения зависимостей.
Расскажите про аннотацию @Qualifier
@Qualifier - это аннотация в Spring Framework, которая используется для разрешения конфликтов при инъекции зависимостей.
Когда в приложении есть несколько бинов (компонентов), которые соответствуют типу и классу, то Spring не может определить, какой из них должен быть использован в конкретном месте, где происходит инъекция зависимости. В этом случае @Qualifier позволяет явно указать, какой именно бин должен быть использован.
Пример использования @Qualifier:
@Service public class UserServiceImpl implements UserService { @Autowired @Qualifier("userRepositoryImpl") private UserRepository userRepository; // ... }
В этом примере мы явно указываем, что для инъекции зависимости UserRepository необходимо использовать бин с именем “userRepositoryImpl”. Без использования @Qualifier Spring не смог бы определить, какой именно бин использовать, если в приложении существует несколько классов, реализующих интерфейс UserRepository.
Расскажите про аннотацию @Value
Аннотация @Value - это аннотация в Spring Framework, которая используется для инъекции значения свойства из внешнего источника в Spring-управляемый компонент.
@Autowired и @Value могут использоваться вместе, чтобы инъектировать значения свойств в Spring-управляемые компоненты, используя имена свойств, которые указываются в @Value.
@Service public class MyService { @Autowired private MyRepository myRepository; @Value("${my.property}") private String myProperty; // ... }
В этом примере мы использовали @Autowired для инъекции MyRepository в поле myRepository класса MyService, а также использовали @Value для инъекции значения свойства my.property в поле myProperty класса MyService. Значение my.property должно быть определено внутри внешнего источника, такого как application.properties или application.yml.
Расскажите про аннотацию @Resource
Java-аннотация @Resource может применяться к классам, полям и методам. Она пытается получить зависимость: сначала по имени, затем по типу, затем по описанию (Qualifier).
Имя извлекается из имени аннотируемого сеттера или поля, либо берется из параметра name.
При аннотировании классов имя не извлекается из имени класса по умолчанию, поэтому оно должно быть указано явно.
Аннотация @Resource является альтернативой аннотации @Autowired в Spring и имеет несколько отличий:
- Поиск бина происходит сначала по имени и затем по типу. Если указано имя бина, то оно будет использоваться для поиска в первую очередь.
- Не нужна дополнительная аннотация для указания имени конкретного бина. Имя бина можно указать непосредственно в аннотации @Resource.
- Нет возможности указать, что место вставки бина является необязательным. В аннотации @Resource отсутствует параметр required, который есть в аннотации @Autowired.
- При замене Spring Framework на другой фреймворк, менять аннотацию @Resource не нужно.
Аннотация @Named
Аннотация @Named является частью JSR 330 (Dependency Injection for Java), которая используется для указания имени для определенного компонента или бина, который может быть использован в DI контейнере.
@Named является альтернативой аннотации @Component, которая является частью Spring Framework. Она используется для маркировки классов, которые будут создаваться и управляться контейнером Spring.
В отличие от @Component, которая создает бин с именем класса, @Named позволяет указать произвольное имя для создаваемого бина. Это позволяет избежать конфликтов имен при создании бинов и облегчает конфигурирование DI контейнера.
@Inject @Named("userService") private UserService userService;
В этом примере мы использовали аннотацию @Inject, которая является частью JSR 330, для внедрения зависимости UserService в наш класс. Мы также использовали @Named для указания имени “userService” для UserService.
Расскажите про аннотацию @Inject
@Inject (аннотация java) – аналог @Autowired (аннотация spring) в первую очередь пытается подключить зависимость по типу, затем по описанию и только потом по имени.
Также стоит отметить, что аннотация @Inject похожа на аннотацию @Autowired в Spring Framework. Однако, в отличие от @Autowired, аннотация @Inject является частью стандарта Java EE и может использоваться в любом контейнере, который поддерживает JSR-330.
Аналог @Autowired - пытается получить зависимость в таком порядке:
1) По типу
2) По описанию
3) По имени
В ней нет параметров, поэтому при использовании бина по Id, используем
@Named
@Inject @Named("someName") private method1()
Расскажите про аннотацию @Lookup
Аннотация @Lookup в Spring Framework используется для внедрения зависимостей с динамическим созданием объектов. Это позволяет создавать новые экземпляры бинов на лету, вместо того, чтобы внедрять один и тот же экземпляр бина в каждый класс, который его требует.
В основе работы аннотации @Lookup лежит использование прокси-объекта, который создается Spring Framework для класса, помеченного этой аннотацией. Когда вызывается метод, помеченный @Lookup, Spring Framework перехватывает вызов и создает новый экземпляр бина на лету.
@Component public class Car { @Lookup public Passenger getPassenger() { // This method will be overridden by Spring // and return a new instance of Passenger every time it's called return null; } public void drive() { Passenger passenger = getPassenger(); // Use the new instance of Passenger // ... } } @Component @Scope("prototype") public class Passenger { // ... }
Аннотация @Lookup в Spring Framework используется для внедрения зависимостей через “look-up” методы. Эти методы определяются в интерфейсах или абстрактных классах, а их конкретная реализация генерируется Spring’ом во время выполнения.
Например, допустим у нас есть интерфейс UserService, который определяет методы для работы с пользователями. В этом интерфейсе мы можем объявить метод getUser, помеченный аннотацией @Lookup, который будет возвращать новый экземпляр User каждый раз, когда он вызывается.
public interface UserService { @Lookup public User getUser(); }
Затем мы можем создать конкретную реализацию этого интерфейса, помеченную аннотацией @Service:
~~~
@Service
public class UserServiceImpl implements UserService {
public User getUser() {
return new User();
}
}
~~~
При каждом вызове метода getUser() будет создаваться новый экземпляр User. Это может быть полезно в некоторых случаях, например, когда необходимо создавать новый объект для каждого запроса или когда объекты должны быть уникальными для каждого потока выполнения.
Аннотация @Lookup позволяет решать несколько задач и преодолевать некоторые проблемы:
- Внедрение prototype бина в singleton бин: Когда необходимо внедрить bean с scope “prototype” в singleton bean, то стандартный подход в Spring не работает, т.к. singleton bean создается только один раз во время запуска приложения, и при каждом вызове метода нужно получать новый экземпляр prototype bean. Для этого можно использовать метод с аннотацией @Lookup, который генерирует новый экземпляр bean при каждом вызове метода.
- Динамическое создание объектов: @Lookup позволяет динамически создавать новые объекты каждый раз, когда это необходимо, вместо того, чтобы использовать один и тот же объект каждый раз.
- Ручное управление жизненным циклом bean: Используя @Lookup, можно управлять жизненным циклом bean вручную, например, создавать объекты только в тех случаях, когда они нужны, или удалять объекты вручную после использования.
Однако, при использовании @Lookup также есть некоторые проблемы:
- Необходимость в абстрактных классах или интерфейсах: чтобы использовать @Lookup, необходимо иметь абстрактный класс или интерфейс, который определяет метод, возвращающий нужный bean. Это может быть неудобно, если вы не хотите создавать лишние классы только для того, чтобы использовать @Lookup.
- Снижение производительности: каждый вызов метода с аннотацией @Lookup приводит к созданию нового экземпляра bean, что может привести к снижению производительности приложения.
- Ограничения использования: @Lookup не может использоваться, если содержащий класс инициализируется через @Bean. Кроме того, метод с аннотацией @Lookup не может быть статическим или final.
Можно ли вставить бин в статическое поле? Почему?
Spring не позволяет внедрять бины напрямую в статические поля. Это связано с тем, что когда загрузчик классов загружает статические значения, контекст Spring еще не загружен.
Если мы попытаемся вставить бин напрямую в статическое поле, как это было описано в предыдущем ответе, то контейнер Spring не сможет управлять этим бином, потому что в момент загрузки класса контекст Spring еще не загружен.
Чтобы исправить это, можно создать нестатический сеттер-метод с @Autowired:
~~~
private static OrderItemService orderItemService;
@Autowired
public void setOrderItemService(OrderItemService orderItemService) {
TestDataInit.orderItemService = orderItemService;
}
~~~
Расскажите про аннотации @Primary и @Qualifier
@Qualifier применяется, если кандидатов для автоматического связывания несколько, аннотация позволяет указать в качестве аргумента имя конкретного бина, который следует внедрить.
Она может быть применена к отдельному полю класса, к отдельному аргументу метода или конструктора
Аннотация @Qualifier позволяет явно указать, какой именно бин нужно внедрить в зависимость. Это полезно в том случае, если у нас есть несколько бинов с одним и тем же типом и необходимо выбрать определенный бин для внедрения в зависимость.
@Primary тоже используется, чтобы отдавать предпочтение бину, когда есть несколько бинов одного типа, но в ней нельзя задать имя бина, она определяет значение по умолчанию.
Аннотация @Primary используется для пометки бина, который будет использоваться по умолчанию в случае, если есть несколько кандидатов на внедрение зависимости одного типа. Например, если у нас есть два бина с одним и тем же типом, то Spring будет использовать тот, который помечен аннотацией @Primary.
при использовании как аннотации @Primary, так и @Qualifier, приоритет будет у @Qualifier. Таким образом, если присутствуют обе аннотации, то Sprin
Например, если есть два бина типа UserService, один помечен аннотацией @Primary, а второй помечен аннотацией @Qualifier(“adminUserService”), то при запросе бина UserService Spring выберет бин с аннотацией @Primary, несмотря на наличие аннотации @Qualifier.
Как заинжектить примитив?
Внедрить в поле примитив можно с помощью аннотации @Value на уровне параметров поля или конструктора/метода.
Нам понадобится файл свойств (*.properties), чтобы определить значения, которые мы хотим внедрить аннотацией @Value. Сначала в нашем классе конфигурации нам нужно указать аннотацию @PropertySource с именем файла свойств.
~~~
@Component
public class MyComponent {
@Value(“10”)
private int myInt;
~~~
@Value(“${some.key}”) public String stringWithDefaultValue;
В эту переменную будет внедрена строка, например, из property или из view.
Кроме того, для внедрения значений можно использовать язык SpEL (Spring Expression Language(
С помощью SpEL можно выполнить арифметические операции, сравнения и логические операции над значениями.
SpEL поддерживает использование переменных, функций и операторов для создания более сложных выражений.).
- @Value with Map
-
@Value with Constructor
~~~
@Autowired
public MyComponent(@Value(“${my.property}”) String value) {
this.value = value;
}
~~~ - @Value with Setter
Как заинжектить коллекцию?
Если внедряемый объект массив, коллекция или map с дженериком, то, используя аннотацию @Autowired, Spring внедрит все бины, подходящие по типу в этот массив (или другую структуру данных). В случае с map ключом будет имя бина.
Используя аннотацию @Qualifier можно настроить тип искомого бина.
Использование аннотации @Inject:
Использование аннотации @Resource:
можно собрать все бины одного типа(например все имплементации какого-либо интерфейса), находящиеся в контейнере, и внедрить их в коллекцию или массив, используя аннотацию @Autowired с квалификатором @Qualifier, указывающим на нужный тип бина. Например, чтобы собрать все бины типа MyBean в список, можно сделать следующее:
@Autowired @Qualifier("myBean") private List<MyBean> myBeans;
Бины могут быть упорядочены, если вставляются в списки (не Set или Map) или массивы. Поддерживаются как аннотация @Order, так и интерфейс Ordered.
Расскажите про аннотацию @Conditional
Аннотация @Conditional позволяет определить условия, которые необходимо учитывать при создании бинов и конфигураций в Spring. Если условие выполняется, то бин или конфигурация будет создана, в противном случае - нет.
Для определения условий необходимо создать классы, реализующие интерфейс Condition, и переопределить его метод matches(). В этом методе можно прописать любую логику проверки условий.
Например, можно проверять наличие определенного свойства в системе, наличие определенного бина в контексте и т.д.
Класс, помеченный аннотацией @Configuration, может быть также помечен и аннотацией @Conditional. В этом случае, все методы, помеченные аннотациями @Bean, @Import и @ComponentScan, будут создаваться только в том случае, если условие, указанное в аннотации @Conditional, выполняется.
Таким образом, использование аннотации @Conditional позволяет гибко настраивать создание бинов и конфигураций в Spring, в зависимости от различных условий.
@Configuration public class AppConfig { @Bean(name = "myBean") @Conditional(MyCondition.class) public MyBean myBean() { return new MyBean(); } } public class MyCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { // Здесь можно реализовать логику проверки условия. // Например, проверка наличия системного свойства с именем "my.property" return System.getProperty("my.property") != null; } } public class MyBean { // Код бина }
В данном примере, при запуске приложения, перед созданием бина “myBean”, будет вызван метод matches() класса MyCondition, где можно проверить выполнение нужного условия. Если условие выполнено, то бин будет создан, иначе - нет.
Класс MyCondition реализует интерфейс Condition и переопределяет его метод matches(). В данном примере, условие проверяет наличие системного свойства с именем “my.property”. Если такое свойство существует, то условие считается выполненным, и бин будет создан. Если свойство не существует, то бин не будет создан.
Расскажите про аннотацию @ComponentScan
Используется для указания пакетов, которые мы хотим сканировать на наличие компонентов, из которых нужно сделать бины.
Используется вместе с аннотацией @Configuration.
@ComponentScan без аргументов указывает Spring по умолчанию сканировать текущий пакет и все его подпакеты. Текущий пакет - тот, в котором находится файл конфигурации с этой самой аннотацией @ComponentScan. В данном случае в контейнер попадут:
* бин конфигурационного класса;
* бины, объявленные в конфигурационном классе с помощью @Bean;
* все бины из пакета и его подпакетов.
Аннотация @SpringBootApplication включает в себя аннотации @ComponentScan, @SpringBootConfiguration и @EnableAutoConfiguration, но это не мешает разместить её ещё раз отдельно для указания конкретного пакета.
Если указать с атрибутом exludeFilters, то это позволит использовать фильтр и исключать ненужные классы из процесса сканирования.
Расскажите про аннотацию @Profile
Профили — это ключевая особенность Spring Framework, позволяющая нам относить наши бины к разным профилям (логическим группам), например, dev, test, prod.
Профиль (Profile) - это набор конфигурационных параметров, который позволяет настроить приложение для разных сценариев использования, таких как разработка, тестирование или продакшн.
С помощью аннотации @Profile мы можем помечать классы или методы конфигурации, которые должны быть активны только для определенных профилей. Например:
~~~
@Configuration
@Profile(“production”)
public class ProductionConfig {
// …
}
@Configuration
@Profile(“development”)
public class DevelopmentConfig {
// …
}
~~~
В данном примере, классы ProductionConfig и DevelopmentConfig помечены аннотацией @Profile соответствующими профилями. Когда мы запускаем приложение, Spring Framework автоматически выбирает только те конфигурации, которые соответствуют текущему профилю.
Чтобы указать текущий профиль, необходимо использовать параметр spring.profiles.active при запуске приложения. Например, для запуска приложения в профиле “production” необходимо выполнить следующую команду:java -jar myapp.jar --spring.profiles.active=production
Также можно указывать несколько профилей через запятую:
java -jar myapp.jar --spring.profiles.active=production,db
Аннотация @Profile может быть использована не только для классов конфигурации, но и для других Spring компонентов, таких как бины, контроллеры и т.д.
В качестве быстрого обозначения имена профилей также могут начинаться с оператора NOT, например «!dev», чтобы исключить их из профиля. В приведенном ниже примере компонент активируется, только если профиль «dev» не активен:
@Component @Profile(\"!dev\") public class DevDatasourceConfig
По умолчанию, если профиль бина не определен, то он относится к профилю “default”.
Spring также предоставляет способ установить профиль по умолчанию, когда другой профиль не активен, используя свойство «spring.profiles.default».
Мы можем активировать разные профили в разных средах, чтобы загрузить только те бины, которые нам нужны.
1) Ее можно применять на уровне класса или метода.
2) Принимает в качестве аргумента имя одного или нескольких профилей.
3) Ее можно ставить на @Configuration и @Component классы
(Фактически реализована на @Conditional)
Расскажите про ApplicationContext и BeanFactory, чем отличаются? В каких случаях что стоит использовать?
BeanFactory
BeanFactory — это интерфейс, который предоставляет механизм конфигурации, способный управлять объектами любого типа. В общем, BeanFactory предоставляет инфраструктуру конфигурации и основные функциональные возможности.
BeanFactory легче по сравнению с ApplicationContext.
ApplicationContext
ApplicationContext является наследником BeanFactory и полностью реализует его функционал, добавляя больше специфических enterprise-функций.
В общем, BeanFactory следует использовать, если вы хотите максимально снизить потребление памяти и производительность важнее, чем функциональность. В то же время, ApplicationContext следует использовать, если вам нужна расширенная функциональность и гибкость управления бинами.
- 1) ApplicationContext загружает все бины при запуске, а BeanFactory - по требованию.
- 2) ApplicationContext расширяет BeanFactory и предоставляет функции, которые подходят для корпоративных приложений: a. поддержка внедрения зависимостей на основе аннотаций; b. удобный доступ к MessageSource (для использования в интернационализации); c. публикация ApplicationEvent - для бинов, реализующих интерфейс ApplicationListener, с помощью интерфейса ApplicationEventPublisher; d. простая интеграция с функциями Spring AOP.
- 3) ApplicationContext поддерживает автоматическую регистрацию BeanPostProcessor и BeanFactoryPostProcessor. Поэтому всегда желательно использовать ApplicationContext, потому что Spring 2.0 (и выше) интенсивно использует BeanPostProcessor.
- 4) ApplicationContext поддерживает практически все типы scope для бинов, а BeanFactory поддерживает только два - Singleton и Prototype.
- 5) В BeanFactory не будут работать транзакции и Spring AOP. Это может привести к путанице, потому что конфигурация с виду будет корректной
- ApplicationContext поддерживает внедрение зависимостей на основе аннотаций, а BeanFactory нет
Подытожив, можно сказать, что для небольших приложений, где достаточно базовых функции подойдет BeanFactory, для более сложных и навороченных, требующих дополнительный функционал, нужен ApplicationContext
BeanFactoryPostProcessor
BeanFactoryPostProcessor. Этот интерфейс позволяет изменять метаданные бинов до их создания. Как правило, BeanFactoryPostProcessor используется для изменения настроек фабрики бинов до того, как она начнет создавать объекты бинов.
Интерфейс BeanFactoryPostProcessor имеет один метод:
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException: Вызывается Spring до создания любых бинов в контексте приложения. ConfigurableListableBeanFactory представляет собой фабрику бинов, которая позволяет изменять метаданные бинов.
Допустим, у нас есть Spring-конфигурация, которая содержит несколько бинов, зависящих от настроек, определенных внутри этой же конфигурации. Мы хотим задать значения этих настроек в зависимости от окружения (например, разработка, тестирование, продакшн). Мы можем использовать BeanFactoryPostProcessor для установки соответствующих значений в зависимости от выбранного окружения.
BeanPostProcessor
BeanPostProcessor. Этот интерфейс предоставляет возможность манипулировать бинами во время их создания. Конкретно, BeanPostProcessor позволяет вносить изменения в бины до того, как они будут использоваться, и после того, как они были созданы.
Интерфейс BeanPostProcessor имеет два метода:
postProcessBeforeInitialization(Object bean, String beanName): Вызывается Spring для всех бинов, после их создания, но перед инициализацией (вызовом метода afterPropertiesSet() для бинов, реализующих InitializingBean, или метода, указанного атрибутом init-method в XML-конфигурации).
postProcessAfterInitialization(Object bean, String beanName): Вызывается Spring для всех бинов, после их инициализации (вызовом метода afterPropertiesSet() для бинов, реализующих InitializingBean, или метода, указанного атрибутом init-method в XML-конфигурации).
BeanPostProcessor часто используется для внедрения дополнительной функциональности в бины, например, для логирования, проверки настроек, кэширования или автоматической регистрации бинов.
Некоторые классы и интерфейсы, связанные с BeanPostProcessor:
BeanPostProcessor: Интерфейс, определяющий методы postProcessBeforeInitialization и postProcessAfterInitialization.
BeanFactoryPostProcessor: Интерфейс, определяющий метод postProcessBeanFactory, который позволяет изменять метаданные бинов до их создания.