Spring Flashcards

1
Q

Что такое инверсия контроля (IoC) и внедрение зависимостей (DI)? Как эти
принципы реализованы в Spring?

A

Inversion of Control – принцип при котором контроль за выполнением программы переходит от программиста к фреймворку.

Dependencies -другие объекты (как правило других классов), с которыми работает и чью функциональность использует текуущий объект.

Dependency Injection является способом реализации принципа IoC в Spring через рефлексию:
IoC-контейнер отвечает за управление жизненным циклом объектов: создание, вызов методов инициализации и конфигурирование объектов через связывание их между собой.
Таким образом, задача программиста - сконфигурировать контейнер, а дальше он всё сделает сам.
Конфигурирование контейнера осуществляется через внедрение аннотаций, через java-code, XML-файлы, и через смесь этих опций.

Spring определяет и внедряет зависимости через (на выбор):
- параметры корструктора
- параметры статического метода реализации (фабричный метод)
- сеттеры (<property/>)

https://habr.com/ru/post/470305/

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Что такое IoC контейнер?

A

Container создаёт объекты, связывает их вместе, настраивает и управляет ими от создания до момента уничтожения.
Объекты хранятся в ассоциативном массиве.

Бины создаются при “поднятии” контекста все сразу. Если не указана стратегия инициализации.

2 типа контейнеров:
1) Spring BeanFactory Container обеспечивает базовую поддержку DI.
BeanFactory обычно используется тогда, когда ресурсы ограничены (мобильные устройства). Поэтому, если ресурсы не сильно ограничены, то лучше использовать ApplicationContext.

2) Spring ApplicationContext Container является более сложным и более продвинутым Spring Container-ом. Наследует BeanFactory и так же загружает бины, связывает их вместе и конфигурирует их определённым образом. Но кроме этого предоставляет дополнительные возможности, например AOP и транзакции.
WebApplicationContext - расширяет ApplicationContext и используется в веб-приложениях.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Что такое Bean в спринге?

A

Бин (bean) — это обычный, как правило не POJO объект, котрый при поднятии контекста будет создан спрингом.

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

Таким образом все публичные переменные класса могут быть изменены одновременно из разных мест, а значит бин - не потокобезопасен. Однако поменяв область действия бина на request, prototype, session он станет потокобезопасным, но это скажется на производительности.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Расскажите про аннотацию @Bean?

A

Аннотация @Bean используется для указания того, что данный метод создает, настраивает и возвращает готовый объект, управляемый IoC-контейнером.
Как правило используется в классах с аннотацией @Configuration,
Может использоваться и в классах с аннотацией @Component (или ее наследниках).
Имеет следующие свойства:
- name - имя (уникальный идентификатор) бина;
- initMethod - имя метода для вызова во время инициализации бина;
- destroyMethod - имя метода для вызова во время удаления бина из контекста;
- autowireCandidate - является ли этот бин кандидатом на автоматическое внедрение в другой бин.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Расскажите про аннотацию @Component?

A

Это аннотация Spring Framework, ею мы помечаем класс, если хотим, чтобы из этого класса был создан бин.
Можно указать имя (Id) для создаваемого бина, а можно не указывать, тогда по умолчанию именем будет название класса с маленькой буквы.

Аннотация @Component имеет наследников:@Configuration, @Repository, @Service и @Controller. Все они являются частными случаями использования @Component для класса конфигурации, слоёв DAO, сервиса и контроллера MVC соответственно.

@Component - Spring определяет этот класс как кандидата для создания bean.

@Service - класс содержит бизнес-логику и вызывает методы на уровне хранилища. Ничем не отличается от классов с @Component.

@Repository - указывает, что класс является слоем, взаимодействующем с ДБ. Задача @Repository заключается в том, чтобы отлавливать исключения персистентности и приводить их к подклассам DataAccessExeption спринга. Для этого Spring оборачивает эти классы в прокси, и в контекст должен быть добавлен класс
@Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() { return new PersistenceExceptionTranslationPostProcessor();}. - спринг делает это автоматически в большинстве случаев.

@Controller - указывает, что класс выполняет роль контроллера MVC. DispatcherServlet просматривает такие классы для поиска @RequestMapping.
@RequestMapping используется для мапинга (связывания) с URL для всего класса или для конкретного метода обработчика.

@Configuration - означает, что класс будет содержать bean definition методы с аннотацией @Bean

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Чем отличаются аннотации @Bean и @Component?

A

Аннотация @Component (как и @Service и @Repository) используется для автоматического обнаружения и автоматической настройки бинов в ходе сканирования путей к классам.

Аннотация @Bean используется для явного объявления бина и позволяет добавить bean, уже реализованного сторонней библиотекой.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Расскажите про аннотации @Service и @Repository. Чем они отличаются?

A

@Service и @Repository являются частными случаями @Component. Технически они одинаковы, но мы используем их для разных целей.

Задача @Repository заключается в том, чтобы отлавливать определенные исключения персистентности и пробрасывать их как одно непроверенное исключение Spring Framework. Для этого в контекст должен быть добавлен класс PersistenceExceptionTranslationPostProcessor.

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Расскажите про аннотацию @Autowired

A

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

  1. Контейнер определяет тип объекта для внедрения.
  2. Контейнер ищет соответствующий тип бина у себя в контексте.
  3. Если есть несколько кандидатов и один из них помечен как @Primary, то внедряется он.
  4. Если используется @Qualifier, то контейнер будет использовать информацию из @Qualifier, чтобы понять, какой компонент внедрять.
  5. В противном случае контейнер внедрит бин, основываясь на его имени или ID.
  6. Если ни один из способов не сработал, то будет выброшено исключение, если не указать @Autowired(required = false)

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

Начиная со 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; }

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Расскажите про аннотацию @Resource

A

Это как Autowired, только аннотация Java
Разница с @Autowired:
ищет бин сначала по имени, а потом по типу;
не нужна дополнительная аннотация для указания имени конкретного бина;
@Autowired позволяет отметить место вставки бина как необязательное @Autowired(required = false);
при замене Spring Framework на другой фреймворк, менять аннотацию @Resource не нужно.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Расскажите про аннотацию @Inject

A

@Inject (аннотация java) – аналог @Autowired (аннотация spring) в первую очередь пытается
подключить зависимость по типу, затем по описанию и только потом по имени.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Расскажите про аннотацию @Lookup

A

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

используется
- для внедрения prototype бина в singletone бин
- для процедурного внедрения зависимостей

Такой бин будет инициализирован не при поднятии контекста, а при вызове метода.

@Lookup
public SchoolNotification getNotification() {
    return null; }

ограничения:
- когда метод находится внутри компонента, он не может быть абстрактным, так как спринг при создании бина скипает абстрактные методы
- аннотация не будет работать, если содержащий класс инициализируется через @Bean

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Можно ли вставить бин в статическое поле? Почему?

A

Spring не позволяет внедрять бины напрямую в статические поля. Это связано с тем, что когда загрузчик классов загружает статические значения, контекст Spring еще не загружен.
Чтобы исправить это, можно создать нестатический сеттер-метод с @Autowired:

private static OrderItemService orderItemService;
@Autowired
public void setOrderItemService(OrderItemService orderItemService) {
TestDataInit.orderItemService = orderItemService;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Расскажите про аннотации @Primary и @Qualifier

A

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

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

Если присутствуют аннотации @Qualifier и @Primary, то аннотация @Qualifier будет иметь приоритет.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Как заинжектить примитив?

A

Для этого можно использовать аннотацию @Value. Можно ставить над полем, конструктором, методом.
Такие значения можно получать из property файлов, из бинов, и т. п.
Чтобы получить из property файла надо над конфиг классов повесить @PropertySource(“classpath:db.properties”)

@Value(“${some.key}”)
public String stringWithDefaultValue;

В эту переменную будет внедрена строка, например, из property или из view.
Кроме того, для внедрения значений можно использовать язык SpEL (Spring Expression Language).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Как заинжектить коллекцию?

A

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

Используя аннотацию @Qualifier можно настроить тип искомого бина.

Бины могут быть упорядочены, если вставляются в списки (не Set или Map) или массивы. Поддерживаются как аннотация @Order, так и интерфейс Ordered.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Расскажите про аннотацию @Conditional

A

Может применяться:
- над классами прямо или косвенно аннотированными @Component включая классы @Configuration;
- над методами @Bean;
- как мета-аннотация при создании наших собственных аннотаций-условий.

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

Аннотация @Conditional указывает, что компонент имеет право на регистрацию в контексте только тогда, когда все условия соответствуют.

Чаще всего используется для включения или исключения целого конфигурационного класса.

Предопределенные условия:
- ConditionalOnBean Условие выполняется, в случае если присутствует нужный бин в BeanFactory.
- ConditionalOnClass Условие выполняется, если нужный класс есть в classpath.
- ConditionalOnExpression Условие выполняется, когда SpEL выражение вернуло положительное значение.
- ConditionalOnProperty Условие выполняется, если в файле настроек заданы нужные параметры.
- ConditionalOnJava Условие выполняется, когда приложение запущено с определенной версией JVM.

Какстомный кондишн:
Создав свой класс и переопределив в нем метод matches() с нашей логикой, мы должны передать этот класс в аннотацию @Conditional в качестве параметра:
@Configuration
@Conditional(OurConditionClass.class)
class MySQLAutoconfiguration {

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

https://www.baeldung.com/spring-conditional-annotations
https://habr.com/ru/post/462541/

17
Q

Расскажите про аннотацию @Profile

A

@ElementType.TYPE, ElementType.METHOD / @Retention (RUNTIME)
Профили — позволяюют нам относить наши бины к разным профилям (логическим группам), например, dev, test, prod.

Используя аннотацию @Profile, мы относим бин к конкретному профилю. Аннотация @Profile принимает в качестве аргумента имя одного или нескольких профилей. Она фактически реализована с помощью гораздо более гибкой аннотации @Conditional.

@Component
@Profile(“dev”) / @Profile(“!dev”)
public class DevDatasourceConfig

Активировать профиль:
- @Autowired
private ConfigurableEnvironment env;
env.setActiveProfiles(“someProfile”);
- JVM System Parameter: -Dspring.profiles.active=dev
- In a Unix environment: export spring_profiles_active=dev
- в тестах: @ActiveProfiles(“dev”)

Дефолнтый профиль:
Все бины, без аннотации относятся к дефолтному профилю. Задать дефолтный профиль в пропертях: spring.profiles.default

Получить активные профили:
@Value(“${spring.profiles.active}”)
private String activeProfile;
Если несколько - будут через запятую

Spring Boot: дал возможность иметь отдельный файл пропертей под каждый профайл: он автоматически подтянет данные в application.properties
из файла .properties названного в соответствии со стандартом:
application-{profile}.properties

18
Q

Расскажите про ApplicationContext и BeanFactory, чем отличаются? В каких
случаях что стоит использовать?

A

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. Это может привести к путанице, потому что конфигурация с виду будет корректной

19
Q

Расскажите про жизненный цикл бина, аннотации @PostConstruct и @PreDestroy()

A

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

Bean Definition (метаинформация) ->
-> Bean Factory Post Processor ->
-> Sorted Bean Definition (Сначала создаются независимые бины, потом, те, которым нужны другие бины) ->
-> forEach(Bean Definition) : Bean constructor -> Setter ->
-> BeanPostProceccor @BeforeInitialization ->
-> @PostConstruct или метод initMethod из аннотации @Bean ->
-> BeanPostProceccor @AfterInitialization ->
-> BEAN IS READY ->
-> @PreDestroy() вызывается только на синглтонах

20
Q

Расскажите про скоупы бинов? Какой скоуп используется по умолчанию? Что
изменилось в пятом спринге?

A

singleton - инициализация произойдет один раз на этапе поднятия контекста. (используется по умолчанию) и все запросы на него будут возвращать один и тот же бин.;
prototype - контейнер Spring IoC создаёт новый экземпляр бина на каждый полученный запрос. Бин будет проходить через все BeanPostProcessor-ы, что может значительно снизить производительность.

Для бинов «prototype» Spring не вызывает метод destroy(), так как не берет на себя контроль полного жизненного цикла этого бина.
Spring не хранит такие бины в своем контексте (контейнере), а отдает их клиенту и больше о них не заботится (в отличие от синглтон-бинов).

4 области видимости в веб-приложении (Касается исключительно ApplicationContext):

request - область видимости – 1 HTTP запрос. На каждый запрос создается новый бин.
session - область видимости – 1 HTTP сессия. На каждую сессию создается новый бин..
web soccet - область видимости – жизненный цикл WebSocket. Создаётся один экземпляр бина для каждого сокета.
application - Создаётся один экземпляр бина для жизненного цикла приложения.

В пятой версии Spring Framework не стало Global session scope. Но появились Application и WebSocket.

21
Q

Расскажите про аннотацию @ComponentScan

A

Аннотация @ComponentScan используется вместе с аннотацией @Configuration для указания пакетов, которые мы хотим сканировать на наличие компонентов, из которых нужно сделать бины.

@ComponentScan без аргументов указывает Spring по умолчанию сканировать текущий пакет и все его подпакеты. Текущий пакет - тот, в котором находится файл конфигурации с этой самой аннотацией @ComponentScan. В данном случае в контейнер попадут:
- бин конфигурационного класса;
- бины, объявленные в конфигурационном классе с помощью @Bean;
- все бины из пакета и его подпакетов.

Аннотация @SpringBootApplication включает в себя аннотации @ComponentScan, @SpringBootConfiguration и @EnableAutoConfiguration, но это не мешает разместить её ещё раз отдельно для указания конкретного пакета.

Если указать @ComponentScan с атрибутом basePackages, то это изменит пакет по умолчанию на указанный:

@ComponentScan(basePackages =
"com.baeldung.componentscan.springapp.animals")
@Configuration
public class SpringComponentScanApp {
// …}

Если указать @ComponentScan с атрибутом excludeFilters, тоэтопозволитиспользовать фильтр и исключить ненужные классы из процесса сканирования:

@ComponentScan(excludeFilters =
@ComponentScan.Filter(type=FilterType.REGEX,
pattern="com\.baeldung\.componentscan\.springapp\.flowers\..*"))

@ComponentScan(excludeFilters =
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {Rose.class, SomeClass.class}))

Для ComponentScan.Filter доступно пять типов фильтров: * ANNOTATION * ASSIGNABLE_TYPE * ASPECTJ * REGEX * CUSTOM

https://www.baeldung.com/spring-component-scanning

22
Q

Как спринг работает с транзакциями? Расскажите про аннотацию
@Transactional.

A

Иначе: как Spring начинает, комитит или откатывает JDBC транзакцию?
Для работы с транзакциями Spring Framework использует AOP-прокси.

@Autowired UserService userservice ->
-> @Transactional UserServiceProxy: Open Transaction, setAutoCommit(false);
-> RealUserService : perform actions ->
-> @Transactional UserServiceProxy: Close Transaction

Аннотация @EnableTransactionManagement означает, что классы, помеченные @Transactional, должны быть обернуты аспектом транзакций. Однако, если мы используем Spring Boot и имеем зависимости spring-data-… или spring-tx, то управление транзакциями будет включено по умолчанию.
Если разместить @Transactional над классом - все его методы станут транзакционными.

1) TransactionInterceptor.invoke() стартует при вызове transactional метода.
2) Он делегируе на TransactionManager определить открывать ли новый EntityMAnager и новую транзакцию.
3) TransactionManager принимает решение, основываясь на следующих фактах:
- выполняется ли хоть одна транзакция в текущий момент или нет;
- атрибута «propagation» у метода, аннотированного @Transactional (для примера, значение REQUIRES_NEW всегда стартует новую транзакцию).

У @Transactional есть ряд параметров:
@Transactional(propagation=Propagation.REQUIRED) - (Если не указано, распространяющееся поведение по умолчанию — REQUIRED.)

REQUIRED – применяется по умолчанию. При входе в @Transactional метод будет использована уже существующая транзакция или создана новая транзакция, если никакой еще нет.
REQUIRES_NEW – новая транзакция всегда создается при входе метод, ранее созданные транзакции приостанавливаются до момента возврата из метода.
NESTED – корректно работает только с базами данных, которые умеют savepoints. При входе в метод в уже существующей транзакции создается savepoint, который по результатам выполнения метода будет либо сохранен, либо отменен. Все изменения, внесенные методом, подтвердятся только позднее с подтверждением всей транзакции. Если текущей транзакции не существует, будет создана новая. (connection.setSavepoint())
MANDATORY – всегда используется существующая транзакция и кидается исключение, если текущей транзакции нет.
SUPPORTS – метод будет использовать текущую транзакцию, если она есть, либо будет исполнятся без транзакции, если ее нет.
NOT_SUPPORTED – при входе в метод текущая транзакция, если она есть, будет приостановлена, и метод будет выполняться без транзакции.
NEVER – явно запрещает исполнение в контексте транзакции. Если при входе в метод будет существовать транзакция, будет выброшено исключение

@Transactional (isolation=Isolation.READ_COMMITTED) - уровень изоляции.
@Transactional(timeout=60) - Сообщает TransactionManager-у о продолжительности времени, чтобы дождаться простоя транзакции, прежде чем принять решение об откате не отвечающих транзакций.
@Transactional(readOnly=false) – разрешает только операции чтения
@Transactional (rollbackFor=Exception.class) - Значение по умолчанию: rollbackFor=RunTimeException.class
@Transactional (noRollbackFor=IllegalStateException.class) - Указывает, что откат не должен происходить, если целевой метод вызывает это исключение.

https://www.marcobehler.com/guides/spring-transaction-management-transactional-in-depth

https://docs.oracle.com/javase/tutorial/jdbc/basics/transactions.html

23
Q

Расскажите про аннотации @Controller и @RestController. Чем они отличаются?
Как вернуть ответ со своим статусом (например 213)?

A

@Controller – специальный тип класса, обрабатывает HTTP-запросы и часто используется с аннотацией @RequestMapping.

@RestController ставится на класс-контроллер вместо @Controller. Она указывает, что этот класс оперирует не моделями, а данными. Она состоит из аннотаций @Controller и @ResponseBody. Была введена в Spring 4.0 для упрощения создания RESTful веб-сервисов.

@ResponseBody сообщает контроллеру, что возвращаемый объект автоматически сериализуется (используя Jackson message converter) в json или xml и передается обратно в объект HttpResponse.

ResponseEntity используется для формирования кастомизированного HTTP-ответа с пользовательскими параметрами (заголовки, код статуса и тело ответа). Во всех остальных случаях достаточно использовать @ResponseBody.

Вернуть свой статус:
- Если хотим использовать ResponseEntity, то должны вернуть его из метода, Spring позаботится обо всем остальном.
return ResponseEntity.status(213);

  • @ResponseStatus(HttpStatus.CREATED)

@PostMapping(value = “/create”)
@ResponseStatus(HttpStatus.CREATED)
public Student createStudent (@RequestBody Student student) {
return service.createStudent(student);
}

@PostMapping(value = “/create”)
public ResponseEntity<Student> createStudent (@RequestBody Student student) {
return new ResponseEntity(service.createStudent(student), HttpStatus.CREATED);
}</Student>

Рест-контроллеры напрямую возвращают объекты Java, которые Spring MVC будет удобно сериализовать в JSON / XML или любой другой формат, который пользователь запросил с помощью HttpMessageConverters.

Однако вы должны убедиться в двух вещах:
1)Имеются соответствующие сторонние библиотеки на пути к классам.
2) Отправлены правильные заголовки Accept или Content-Type с каждым запросом.

24
Q

Что такое ViewResolver?

A

Класс, который пытается найти View, должен реализовать ViewResolver.
ViewResolver сопоставляет имена представлений, возвращаемых методами контроллеров, с фактическими представлениями (html-файлами). Spring Framework поставляется с довольно большим количеством ViewResolver, например InternalResourceViewResolver (default), XmlViewResolver, ResourceBundleViewResolver и несколькими другими.

Существует также несколько реализаций для интеграции с различными технологиями представлений, например Thymeleaf (ThymeleafViewResolver)

Spring Boot автоматически настраивает ViewResolver каждый раз, когда вы добавляете в свой проект зависимость, такую как spring-boot-starter-thymeleaf.
Он также настраивает ViewResolver так, чтобы он по умолчанию просматривал ваш каталог src/main/resources/template.

25
Q

Чем отличаются Model, ModelMap и ModelAndView?

A

Model - интерфейс, представляет коллекцию пар ключ-значение Map<String, Object>. Содержимое модели используется для отображения данных во View.
Например, если View выводит информацию об объекте Customer, то она может ссылаться к ключам модели, например customerName, customerPhone, и получать значения для этих ключей.
Объекты-значения из модели также могут содержать бизнес-логику.

ModelMap - класс, реализует Model и наследуется от LinkedHashMap, используется для передачи значений для визуализации представления.
Преимущество ModelMap заключается в том, что он дает нам возможность передавать коллекцию значений и обрабатывать эти значения, как если бы они были внутри Map.

Следует отметить, что в Model и ModelMap мы можем хранить только данные. Мы помещаем данные и возвращаем имя представления.

ModelAndView - это просто контейнер для ModelMap, объекта View и HttpStatus. Это позволяет контроллеру возвращать все значения как одно.
View используется для отображения данных приложения пользователю.
Spring MVC поддерживает несколько поставщиков View(они называются шаблонизаторы) — JSP, JSF, Thymeleaf, и т.п.
Интерфейс View преобразует объекты в обычные сервлеты.”

26
Q

Расскажите про паттерн MVC, как он реализован в Spring?

A

MVC (Model-View-Controller)
Это шаблон проектирования программного обеспечения, который делит программную логику на три отдельных, но взаимосвязанных компонента: модель, представление и контроллер — таким образом, что модификация каждого компонента может осуществляться независимо.

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

Представление (View) отвечает за отображение пользователю данных из модели в нужном формате.

Контроллер (Controller) содержит код, который отвечает за обработку действий пользователя и обменивается данными с моделью (любое действие пользователя в системе обрабатывается в контроллере).

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

При написании веб-приложений на Java с использованием Spring или без него мы пишем приложения, которые возвращают два разных формата данных:
1 HTML → приложение создает HTML-страницы, которые можно просматривать в браузере.
2. JSON/XML → приложение предоставляет сервисы RESTful, которые генерируют JSON или XML.

Spring MVC - веб-фреймворк, основанный на Servlet API, предназначенный для создания веб-приложений на языке Java, с использованием двух самых популярных шаблонов проектирования - Front controller и MVC.

Front controller (Единая точка входа) - паттерн, где центральный сервлет, DispatcherServlet, принимает все запросы и распределяет их между контроллерами, обрабатывающими разные URL.

**
последовательность событий, соответствующая входящему HTTP- запросу:
**
1) После получения HTTP-запроса DispatcherServlet обращается к интерфейсу HandlerMapping, который по аннотации @RequestMapping определяет, какой Контроллер (Controller) должен быть вызван, после чего HandlerAdapter, отправляет запрос в нужный метод Контроллера.
2) Контроллер принимает запрос и вызывает соответствующий служебный метод, основанный на GET, POST и т.д. Вызванный метод формирует данные Модели (например, набор данных из БД) и возвращает их в DispatcherServlet вместе с именем Представления (View) (как правило имя html-файла).
3) При помощи интерфейса ViewResolver DispatcherServlet определяет, какое Представление нужно использовать на основании полученного имени и получает в ответе имя представления View.
- Если это REST-запрос на сырые данные (JSON/XML), то DispatcherServlet сам его отправляет;
- Если обычный запрос, то DispatcherServlet отправляет данные Модели в виде атрибутов в Представление (View) - шаблонизаторы Thymeleaf, FreeMarker и т.д., которые сами отправляют ответ.

https://habr.com/ru/post/500572/

27
Q

Расскажите про паттерн Front Controller, как он реализован в Spring?

A

Паттерн Front Controller обеспечивает единую точку входа для всех входящих запросов.

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

Почти все веб-фреймворки Java основаны на сервлетах, поэтому Spring MVC также нужен сервлет, который обрабатывает каждый входящий HTTP-запрос: поэтому фронт-контроллер реализован в виде DispatcherServlet extends HttpServlet.

Иногда необходимо определить два и более DispatcherServlet-а.
Например, чтобы один обрабатывал REST-запросы с маппингом “/api”, а другой обычные запросы с маппингом “/default”:

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

ContextLoaderListener создает корневой контекст приложения (Root WebApplicationContext extends ApplicationContext) и он будет использоваться всеми дочерними контекстами, созданными всеми DispatcherServlet.
Корневой контекст приложения будет общим и может быть только один.
Он содержит компоненты, которые видны всем дочерним контекстам, такие как сервисы, репозитории, компоненты инфраструктуры и т.д.

Каждый DispatcherServlet создаёт себе один дочерний WebApplicationContext.

28
Q

Что такое АОП? Как реализовано в спринге?

A

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

Ключевые понятия:
- сквозная функциональность: затрагивает несколько модулей, но она не имеет прямого отношения к бизнес коду, и ее хорошо бы вынести в отдельное место
- Aspect: модуль в котором собраны описания Pointcut и Advice.

  • Join point: точка присоединения к коду, где планируется внедрение функциональности. В Spring AOP это всегда выполнение метода.
  • Pointcut: это предикат, вычисляет Join points. (можно: ?? / || / !)
  • Advice: набор инструкций выполняемых на точках среза (Pointcut). Инструкции можно выполнять по событию разных типов:
    Before — перед вызовом метода
    After — после вызова метода
    After returning — после возврата значения из функции
    After throwing — в случае exception
    After finally — в случае выполнения блока finally
    Around — можно сделать пред., пост., обработку перед вызовом метода, а также вообще обойти вызов метода.

на один Pointcut можно «повесить» несколько Advice разного типа.

AspectJ де-факто является стандартом реализации АОП.
Spring AOP поддерживает аннотации AspectJ, таким образом мы можем работать в спринг проекте похожим образом с AspectJ проектом.
Реализация АОП от Spring имеет некоторые отличия:

  • в Spring AOP нет необходимости следить за процессом связывания.
  • Spring + AOP поддерживает только proxy-based АОП и может использовать только один тип точек соединения - Method Invocation. AspectJ поддерживает все виды точек соединения.
  • Spring AOP работает только со своими бинами, которые существуют в Spring Context.

Interceptor вставляет Элементы АОП в алгоритм выполнение программы.

@Service
public class MyService {

    @AspectAnnotation
    public void method2() {
        System.out.println("MyService method2");
    }
}

@Aspect
@Component
public class MyAspect {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

@Pointcut("@annotation(AspectAnnotation)")
public void callAtMyServiceAnnotation() { }

    @Before("callAtMyServiceAnnotation()")
    public void beforeCallAtMethod1(JoinPoint jp) {
        logger.info("before " + jp.toString() + ", args=[" + args + "]");
    }

    @After("callAtMyServiceAnnotation()")
    public void afterCallAt(JoinPoint jp) {
        logger.info("after " + jp.toString());
    }
}

https://habr.com/ru/post/428548/

29
Q

В чем разница между Filters, Listeners and Interceptors?

A

Filter: находится снаружи и не является частью Spring MVC:
может перехватывать HTTP request/responce на входе / выходе в / из Dispatcher Servlet. Подходит для
- аутентификации
- логирования in/out запросов
- компресии / декомпрессии
- любого функционала, который мы хотим отделить от Spring MVC

HandlerInterceptors - часть Spring MVC и находятся между Dispatcher Servlet и контроллерами. В частности являются инструментом внедрения AOP.
Следует знать, что HandlerInterceptor связан с бином DefaultAnnotationHandlerMapping, который отвечает за применение перехватчиков к любому классу, помеченному аннотацией @Controller.

ServletContextListener

Java Listener
Listener (Слушатель) - это класс, который реализует интерфейс javax.servlet.ServletContextListener. Он инициализируется только один раз при запуске веб-приложения и уничтожается при остановке веб-приложения. Слушатель сидит и ждет, когда произойдет указанное событие, затем «перехватывает» событие и запускает собственное событие. Например, мы хотим инициализировать пул соединений с базой данных до запуска веб-приложения. ServletContextListener - это то, что нам нужно, он будет запускать наш код до запуска веб-приложения.

Все ServletContextListeners уведомляются об инициализации контекста до инициализации любых фильтров или сервлетов в веб-приложении.

Все ServletContextListeners уведомляются об уничтожении контекста после того, как все сервлеты и фильтры уничтожены.

Чтобы создать свой Listener нам достаточно создать класс, имплементирующий интерфейс ServletContextListener и поставить над ним аннотацию @WebListener:
~~~
@WebListener
public class MyAppServletContextListener
implements ServletContextListener{
//Run this before web application is started
@Override
public void contextInitialized(ServletContextEvent arg0) {
System.out.println("ServletContextListener started");
}
@Override
public void contextDestroyed(ServletContextEvent arg0) {
System.out.println("ServletContextListener destroyed");
}}
~~~

30
Q

Можно ли передать в запросе один и тот же параметр несколько раз? Как?

A

Да, можно принять все значения, используя массив в методе контроллера:

http://localhost:8080/login?name=Ranga&name=Ravi&name=Sathish
public String method(@RequestParam(value="name") String[] names){...}
http://localhost:8080/api/foos?id=1,2,3
public String getFoos(@RequestParam List<String> id){...}
31
Q

Как работает Spring Security? Как сконфигурировать? Какие интерфейсы
используются? (11)

A

Spring Security работает через интерфейс Filter (прехватывает все входящие http-запросы) и представляет из себя список фильтров в виде класса FilterChainProxy, интегрированного в контейнер сервлетов.
FilterChainProxy содержит Collection<SecurityFilterChain> с методами
~~~
- boolean matches(HttpServletRequest request);
- List<Filter> getFilters();
~~~
Каждый фильтр реализует какой-то механизм безопасности. Важна последовательность фильтров в цепочке.</Filter>

Когда мы добавляем аннотацию @EnableWebSecurity то между запросом и сервлетом добавляется DelegatingFilterProxy, его задача заключается в том, чтобы вызвать цепочку фильтров (FilterChainProxy) из Spring Security.

Процесс аутентификации:
1) AuthenticationManager проитерируется по всем настроенным AuthenticationProviderам которые принимают и отдают объект Authentication после вызова authenticate().

2) на входе объект Authentication содержит объект Credentials,и если на выходе он дополняется объектом Principal - аутентификация имеет успех.

3) Каждый раз, когда юзер будет делать запрос к приложению, оно будет иметь доступ к объекту Authentication юзера, который хранится в Session:
Cookie<String, String> - пара ключ:значение(ex: id=11), хранится в браузере и при каждом запросе посылается на сервер и если на сервере есть HttpSession(хранит attribute<Sting, Object>) с таким id - пользователь аутентифицирован. Из сессии берется объект Authentication (содержит Principal) и помещается в поток этого юзера, и доступно только этому потоку.

Если мы хотим настроить свою цепочку фильтров, раньше можно было создать класс имплементировав интерфейс WebSecurityConfigurerAdapter переопределив метод configure(). Spring теперь рекомендует создавать bean, возвращающий SecurityFilterChain:

@Configuration
public class SecurityConfiguration {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests((authz) -> authz
                .anyRequest().authenticated()
            )
            .httpBasic(withDefaults());
        return http.build();
    }}

Основные Интерфейсы:
1) SecurityContext -контейнер для объекта типа Authentication. (Аналог - ApplicationContext, в котором лежат бины).
Имеет только два метода: getAuthentication() и setAuthentication(Authentication authentication).
По умолчанию на каждый поток создается один SecurityContext.

2) SecurityContextHolder - Класс, хранящий в ThreadLocal SecurityContext-ы для каждого потока, и содержащий статические методы для работы с SecurityContext-ами, а через них с текущим объектом Authentication, привязанным к нашему веб-запросу.

3) Authentication - объект, отражающий информацию о текущем пользователе и его привилегиях. Хранит объекты Principal, Credentials, Collection<GrantedAuthority>.

4) Principal - интерфейс из пакета java.security, отражающий учетную запись пользователя.
В терминах логин-пароль это логин. В интерфейсе Authentication есть метод getPrincipal(), возвращающий Object. При аутентификации с использованием имени пользователя/пароля Principal реализуется объектом типа UserDetails.

5) Credentials - любой Object; то, что подтверждает учетную запись пользователя, как правило пароль (отпечатки пальцев, пин - всё это Credentials, а владелец отпечатков и пина - Principal).

6) GrantedAuthority - полномочия, предоставленные пользователю, например, роли или уровни доступа.

7) UserDetails - интерфейс, представляющий учетную запись пользователя. Как правило модель нашего пользователя должна имплементировать его. Она просто хранит пользовательскую информацию в виде логина, пароля и флагов isAccountNonExpired, isAccountNonLocked, isCredentialsNonExpired, isEnabled, а также коллекции прав (ролей) пользователя. Данная информация позже инкапсулируется в объекты Authentication.

8) UserDetailsService - интерфейс объекта, реализующего загрузку пользовательских данных из хранилища. Созданный нами объект с этим интерфейсом должен обращаться к БД и получать оттуда юзеров.

9) AuthenticationManager - основной стратегический интерфейс для аутентификации.

10) AuthenticationProvider - интерфейс объекта, выполняющего аутентификацию.
AuthenticationProvider немного похож на AuthenticationManager, но у него есть дополнительный метод, позволяющий вызывающей стороне спрашивать, поддерживает ли он переданный ему объект Authentication, возможно этот AuthenticationProvider может поддерживать только аутентификацию по логину и паролю, но не поддерживать Google-аутентификацию: boolean supports(java.lang.Class<?> authentication)

11) PasswordEncoder - интерфейс для шифрования/расшифровывания паролей. Одна из популярных реализаций - BCryptPasswordEncoder.

32
Q

Что такое SpringBoot? Какие у него преимущества? Как конфигурируется?
Подробно.

A

Spring Boot - это модуль Spring-а, который предоставляет функцию RAD для среды Spring (Rapid Application Development - Быстрая разработка приложений).

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

Ключевые особенности и преимущества Spring Boot:

1) Простота управления зависимостями (spring-boot-starter-* в pom.xml).

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

Например, если вы хотите начать использовать Spring Data JPA для доступа к базе данных, просто включите в свой проект зависимость spring-boot-starter-data-jpa (вам не придется искать совместимые драйверы баз данных и библиотеки Hibernate). Если вы хотите создать Spring web-приложение, просто добавьте зависимость spring-boot-starter-web, которая подтянет в проект все библиотеки, необходимые для разработки Spring MVC-приложений, таких как spring-webmvc, jackson-json, validation-api и Tomcat.

Другими словами, Spring Boot собирает все общие зависимости и определяет их в одном месте, что позволяет разработчикам просто их использовать. Также при использовании Spring Boot, файл pom.xml содержит намного меньше строк, чем в Spring-приложениях.

2) Автоматическая конфигурация.
Автоматическая конфигурация включается аннотацией @EnableAutoConfiguration. (входит в состав аннотации @SpringBootApplication) После выбора необходимых для приложения starter-пакетов Spring Boot попытается автоматически настроить Spring-приложение на основе выбранных jar-зависимостей, доступных в classpath классов, свойств в application.properties и т.п.

Например, если добавим spring-boot-starter-web, то Spring boot автоматически сконфигурирует такие бины как DispatcherServlet, ResourceHandlers, MessageSource итд

Автоматическая конфигурация работает в последнюю очередь, после регистрации пользовательских бинов и всегда отдает им приоритет. Если ваш код уже зарегистрировал бин DataSource — автоконфигурация не будет его переопределять.

3) Встроенная поддержка сервера приложений/контейнера сервлетов (Tomcat, Jetty, итд).
Каждое Spring Boot web-приложение включает встроенный web-сервер. Не нужно беспокоиться о настройке контейнера сервлетов и развертывания приложения в нем.

Теперь приложение может запускаться само как исполняемый .jar-файл с использованием встроенного сервера.

Готовые к работе функции, такие как метрики, проверки работоспособности, security и внешняя конфигурация.
Инструмент CLI (command-line interface) для разработки и тестирования приложения Spring Boot.
Минимизация boilerplate кода (код, который должен быть включен во многих местах практически без изменений), конфигурации XML и аннотаций.

Как происходит автоконфигурация в Spring Boot:
1. Отмечаем main класс аннотацией @SpringBootApplication (аннотация инкапсулирует в себе: @SpringBootConfiguration, @ComponentScan, @EnableAutoConfiguration), таким образом наличие @SpringBootApplication включает сканирование компонентов, автоконфигурацию и показывает разным компонентам Spring (например, интеграционным тестам), что это Spring Boot приложение.

  1. @EnableAutoConfiguration импортирует класс EnableAutoConfigurationImportSelector. Этот класс не объявляет бины сам, а использует фабрики.
  2. Класс EnableAutoConfigurationImportSelector импортирует ВСЕ (более 150) перечисленные в META-INF/spring.factories конфигурации, чтобы предоставить нужные бины в контекст приложения.
  3. Каждая из этих конфигураций пытается сконфигурировать различные аспекты приложения (web, JPA, AMQP и т.д.), регистрируя нужные бины. Логика при регистрации бинов управляется набором @ConditionalOn* аннотаций. Можно указать, чтобы бин создавался при наличии класса в classpath (@ConditionalOnClass), наличии существующего бина (@ConditionalOnBean), отсуствии бина (@ConditionalOnMissingBean) и т.п. Таким образом наличие конфигурации не значит, что бин будет создан и зачастую конфигурация ничего делать и создавать не будет.
  4. Созданный в итоге AnnotationConfigEmbeddedWebApplicationContext ищет в том же DI контейнере фабрику для запуска embedded servlet container.
  5. Servlet container запускается, приложение готово к работе
33
Q

Расскажите про нововведения Spring 5.

A

“● Используется JDK 8+ (Optional, CompletableFuture, Time API, java.util.function, default methods)
● Поддержка JUnit 5 + Testing Improvements (conditional and concurrent)
● Spring-Data-JPA 2.x, Spring-Security 5.x
● Поддержка Java 9 (Automatic-Module-Name in 5.0, module-info in 6.0+, ASM 6)
● Поддержка HTTP/2 (TLS, Push), NIO/NIO.2
● Поддержка Kotlin
● Реактивность (веб-инфраструктура с реактивным стеком, «Spring WebFlux»)
● Null-safety аннотации(@Nullable), новая документация
● Совместимость с Java EE 8 (Servlet 4.0, Bean Validation 2.0, JPA 2.2, JSON Binding API 1.0)
● Удалена поддержка: Portlet, Velocity, JasperReports, XMLBeans, JDO, Guava”