Главная страница
Навигация по странице:

  • Что произойдет, если один метод с @Transactional вызовет другой метод с

  • Что произойдет, если один метод БЕЗ @Transactional вызовет другой

  • Будет ли транзакция отменена, если будет брошено исключение, которое

  • Расскажите про аннотации @Controller и @RestController. Чем они

  • Что такое ViewResolver

  • InternalResourceViewResolver

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

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

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

  • DispatcherServlet

  • WebApplicationContext .HandlerMapping

  • Controller

  • HandlerAdapter

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

  • Совет (advice)

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

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

  • ОглавлениеCore


    Скачать 1.53 Mb.
    НазваниеОглавлениеCore
    Дата17.05.2023
    Размер1.53 Mb.
    Формат файлаpdf
    Имя файлаpolnaya_metodichka (1).pdf
    ТипДокументы
    #1138113
    страница23 из 25
    1   ...   17   18   19   20   21   22   23   24   25
    Подробно:
    Для работы с транзакциями Spring Framework использует AOP-прокси:
    Для включения возможности управления транзакциями нужно разместить аннотацию
    @EnableTransactionManagement у класса конфигурации @Configuration.
    Она означает, что классы, помеченные @Transactional, должны быть обернуты аспектом транзакций. Отвечает за регистрацию необходимых компонентов Spring, таких как
    TransactionInterceptor и советы прокси. Регистрируемые компоненты помещают перехватчик в стек вызовов при вызове методов @Transactional. Если используем Spring Boot и имеем зависимости spring-data-* или spring-tx, то управление транзакциями будет включено по умолчанию.
    Пропагейшн работает, только если метод вызывает другой метод в другом сервисе. Если метод вызывает другой метод в этом же сервисе, то используется this и вызов проходит мимо прокси. Это ограничение можно обойти при помощи self-injection.
    Слой логики (Service) – лучшее место для @Transactional.
    Если пометить @Transactional класс @Service, то все его методы станут транзакционными.
    Так, при вызове, например, метода save() произойдет примерно следующее:
    1. Вначале имеем:

    класс TransactionInterceptor, у которого вызывается метод invoke(...), внутри которого вызывается метод класса-родителя
    TransactionAspectSupport:
    invokeWithinTransaction(...), в рамках которого происходит магия транзакций.

    TransactionManager: решает, создавать ли новый EntityManager и/или транзакцию.

    EntityManager proxy: EntityManager – это интерфейс, и то, что внедряется в бин в слое
    DAO на самом деле не является реализацией EntityManager. В это поле внедряется
    EntityManager proxy, который будет перехватывать обращение к полю EntityManager и делегировать выполнение конкретному EntityManager в рантайме. Обычно
    EntityManager proxy представлен классом SharedEntityManagerInvocationHandler.

    2. Transaction Interceptor.
    В TransactionInterceptor отработает код до работы метода save(), в котором будет определено, выполнить ли метод save() в пределах уже существующей транзакции БД или должна стартовать новая отдельная транзакция. TransactionInterceptor сам не содержит логики по принятию решения, решение начать новую транзакцию, если это нужно,
    делегируется TransactionManager. Грубо говоря, на данном этапе метод будет обернут в try- catch и будет добавлена логика до его вызова и после:
    try {
    transaction.begin(); // логика до
    service.save();
    transaction.commit(); // логика после
    } catch(Exception ex) {
    transaction.rollback();
    throw ex;
    }
    3. TransactionManager.
    Менеджер транзакций должен предоставить ответ на два вопроса:

    должен ли создаться новый EntityManager?

    должна ли стартовать новая транзакция БД?
    Решение принимается, основываясь на следующих фактах:

    выполняется ли хоть одна транзакция в текущий момент или нет;

    атрибута «propagation» в @Transactional.
    Если TransactionManager решил создать новую транзакцию, тогда:

    создается новый EntityManager;

    EntityManager «привязывается» к текущему потоку (Thread);

    «получается» соединение из пула соединений БД;

    соединение «привязывается» к текущему потоку.
    И EntityManager и соединение привязываются к текущему потоку, используя переменные
    ThreadLocal.
    4. EntityManager proxy.
    Если метод save() слоя Service делает вызов метода save() слоя DAO, внутри которого вызывается, например, entityManager.persist(), то не происходит вызов метода persist()
    напрямую у EntityManager, записанного в поле класса DAO. Вместо этого метод вызывает
    EntityManager proxy, который достает текущий EntityManager для потока, и у него вызывается метод persist().
    5. Отрабатывает DAO-метод save().
    6. TransactionInterceptor.

    Отработает код после работы метода save(). Другими словами, будет принято решение по коммиту/откату транзакции.
    Кроме того, если в рамках одного метода сервиса обращаемся не только к методу save(), а к разным методам Service и DAO, то все они буду работать в рамках одной транзакции,
    которая оборачивает данный метод сервиса.
    Вся работа происходит через прокси-объекты разных классов. Представим, что у нас в классе сервиса только один метод с аннотацией @Transactional, а остальные нет. Если вызовем метод с @Transactional, из которого вызовем метод без @Transactional, то оба будут отработаны в рамках прокси и будут обернуты в нашу транзакционную логику. Однако, если вызовем метод без @Transactional, из которого вызовем метод с @Transactional, то они уже не будут работать в рамках прокси и не будут обернуты в транзакционную логику.
    Что произойдет, если один метод с @Transactional вызовет другой метод с
    @Transactional?
    Если это происходит в рамках одного сервиса, то второй транзакционный метод будет считаться частью первого, так как вызван у него изнутри, а так как спринг не знает о внутреннем вызове, то не создаст прокси для второго метода.
    Что произойдет, если один метод БЕЗ @Transactional вызовет другой
    метод с @Transactional?
    Так как Spring не знает о внутреннем вызове, то не создаст прокси для второго метода.
    Будет ли транзакция отменена, если будет брошено исключение, которое
    указано в контракте метода?
    Если в контракте описано это исключение, то она не откатится. Unchecked-исключения в транзакционном методе можно ловить, а можно и не ловить.
    Расскажите про аннотации @Controller и @RestController. Чем они
    отличаются? Как вернуть ответ со своим статусом (например 213)?
    @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);

    Что такое ViewResolver?
    ViewResolver – распознаватель представлений, это способ работы с представлениями
    (html-файлы), который поддерживает их распознавание на основе имени, возвращаемого контроллером.
    Spring Framework поставляется с большим количеством реализаций ViewResolver.
    Например, класс UrlBasedViewResolver поддерживает прямое преобразование логических имен в URL.
    InternalResourceViewResolver – реализация ViewResolver по умолчанию, которая позволяет находить представления, которые возвращает контроллер для последующего перехода к ним. Ищет по заданному пути, префиксу, суффиксу и имени.
    Любым реализациям ViewResolver желательно поддерживать интернационализацию, то есть множество языков.
    Существует также несколько реализаций для интеграции с различными технологиями представлений, такими как FreeMarker (FreeMarkerViewResolver), Velocity
    (VelocityViewResolver) и JasperReports (JasperReportsViewResolver).
    Чем отличаются Model, ModelMap и ModelAndView?
    Model – интерфейс, представляет коллекцию пар ключ-значение Map.
    Содержимое модели используется для отображения данных во View.
    Например, если View выводит информацию об объекте Customer, то она может ссылаться к ключам модели, например, customerName, customerPhone, и получать значения для этих ключей.
    Объекты-значения из модели также могут содержать бизнес-логику.
    ModelMap – класс, наследуется от LinkedHashMap, используется для передачи значений для визуализации представления.
    Преимущество ModelMap заключается в том, что он дает возможность передавать коллекцию значений и обрабатывать эти значения, как если бы они были внутри Map.
    ModelAndView – это контейнер для ModelMap, объект View и HttpStatus. Это позволяет контроллеру возвращать все значения как одно.
    View используется для отображения данных приложения пользователю.
    Spring MVC поддерживает несколько поставщиков View (они называются шаблонизаторы) –
    JSP, JSF, Thymeleaf, и т. п.
    Интерфейс View преобразует объекты в обычные сервлеты.
    Расскажите про паттерн Front Controller, как он реализован в Spring?
    Front Controller обеспечивает единую точку входа для всех входящих запросов. Все запросы обрабатываются одним обработчиком – DispatcherServlet с маппингом “/”. Этот обработчик может выполнить аутентификацию, авторизацию, регистрацию или отслеживание запроса, а затем распределяет их между контроллерами, обрабатывающими разные URL. Это и есть реализация паттерна Front Controller.

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

    один из контекстов будет корневым, а все остальные контексты будут дочерними;

    все дочерние контексты могут получить доступ к бинам, определенным в корневом контексте, но не наоборот;

    каждый дочерний контекст внутри себя может переопределить бины из корневого контекста.
    WebApplicationContext расширяет ApplicationContext (создает и управляет бинами и т. д.), но помимо этого имеет дополнительный метод getServletContext(), через который у него есть возможность получать доступ к ServletContext-у.
    ContextLoaderListener создает корневой контекст приложения и будет использоваться всеми дочерними контекстами, созданными всеми DispatcherServlet-ами.
    Расскажите про паттерн MVC, как он реализован в Spring?
    MVC – это шаблон проектирования, делящий программу на 3 вида компонентов:
    1. Model – модель отвечает за хранение данных.
    2. View – отвечает за вывод данных на фронтенде.
    3. Controller – оперирует моделями и отвечает за обмен данными model с view.
    Основная цель следования принципам MVC – отделить реализацию бизнес-логики приложения (модели) от ее визуализации (view).
    Spring MVC – это веб-фреймворк, основанный на Servlet API с использованием двух шаблонов проектирования Front controller и MVC.
    Spring MVC реализует четкое разделение задач, что позволяет легко разрабатывать и тестировать приложения. Данные задачи разбиты между разными компонентами: Dispatcher
    Servlet, Controllers, View Resolvers, Views, Models, ModelAndView, Model and Session
    Attributes, которые полностью независимы друг от друга и отвечают только за одно направление. Поэтому MVC предоставляет большую гибкость. Он основан на интерфейсах
    (с классами реализации), и можно настраивать каждую часть фреймворка с помощью пользовательских интерфейсов.
    Основные интерфейсы для обработки запросов:
    DispatcherServlet является главным контроллером, который получает запросы и распределяет их между другими контроллерами. @RequestsMapping указывает, какие именно запросы будут обрабатываться в конкретном контроллере. Может быть несколько экземпляров DispatcherServlet, отвечающих за разные задачи (обработка запросов пользовательского интерфейса, REST служб и т. д.). Каждый экземпляр DispatcherServlet имеет собственную конфигурацию WebApplicationContext.
    HandlerMapping. Выбор класса и его метода, которые должны обработать данный входящий запрос на основе любого внутреннего или внешнего для этого запроса атрибута или состояния.
    Controller оперирует моделями и отвечает за обмен данными model с view.

    ViewResolver. Выбор, какое именно View должно быть показано клиенту на основе имени,
    полученного от контроллера.
    View. Отвечает за возвращение ответа клиенту в виде текстов и изображений. Используются встраиваемые шаблонизаторы (Thymeleaf, FreeMarker и т. д.), так как у Spring нет родных.
    Некоторые запросы могут идти прямо во View, не заходя в Model, другие проходят через все слои.
    HandlerAdapter. Помогает DispatcherServlet вызвать и выполнить метод для обработки входящего запроса.
    ContextLoaderListener – слушатель при старте и завершении корневого класса Spring
    WebApplicationContext. Основным назначением является связывание жизненного цикла
    ApplicationContext и ServletContext, а также автоматического создания ApplicationContext.
    Можно использовать этот класс для доступа к бинам из различных контекстов спринга.
    Ниже приведена последовательность событий, соответствующая входящему HTTP-запросу:

    после получения HTTP-запроса DispatcherServlet обращается к интерфейсу
    HandlerMapping, который определяет, какой контроллер (Controller) должен быть вызван, после чего HandlerAdapter отправляет запрос в нужный метод контроллера;

    контроллер принимает запрос и вызывает соответствующий метод, вызванный метод формирует данные Model и возвращает их в DispatcherServlet вместе с именем View
    (как правило имя html-файла);

    при помощи интерфейса ViewResolver DispatcherServlet определяет, какое View нужно использовать на основании имени, полученного от контроллера;

    если это REST-запрос на сырые данные (JSON/XML), то DispatcherServlet сам его отправляет, минуя ViewResolver;

    если обычный запрос, то DispatcherServlet отправляет данные Model в виде атрибутов во View-шаблонизаторы Thymeleaf, FreeMarker и т. д., которые сами отправляют ответ.
    Таким образом, все действия происходят через один DispatcherServlet.

    Что такое АОП? Как реализовано в спринге?
    Аспектно-ориентированное программирование (АОП)
    – это парадигма программирования, целью которой является повышение модульности за счет разделения междисциплинарных задач. Это достигается путем добавления дополнительного поведения к существующему коду без изменения самого кода.
    АОП предоставляет возможность реализации сквозной логики в одном месте, т. е. логики,
    которая применяется к множеству частей приложения, и обеспечения автоматического применения этой логики по всему приложению.
    Аспект в АОП – это модуль или класс, реализующий сквозную функциональность. Аспект изменяет поведение остального кода, применяя совет в точках соединения, определенных некоторым срезом.
    Совет (advice) – дополнительная логика, код, который должен быть вызван из точки соединения.
    Точка соединения (join point) – место в выполняемой программе (вызов метода, создание объекта, обращение к переменной), где следует применить совет.
    Срез (pointcut) – набор точек соединения.
    Подход Spring к АОП заключается в создании «динамических прокси» для целевых объектов и «привязывании» объектов к конфигурированному совету для выполнения сквозной логики.
    Есть два варианта создания прокси-класса:

    либо он должен наследоваться от оригинального класса (CGLIB) и переопределять его методы, добавляя нужную логику;

    либо он должен имплементировать те же самые интерфейсы, что и первый класс
    (Dynamic Proxy).
    В чем разница между Filters, Listeners and Interceptors?
    Filter выполняет задачи фильтрации либо по пути запроса к ресурсу, либо по пути ответа от ресурса, либо в обоих направлениях.
    Фильтры выполняют фильтрацию в методе doFilter. Каждый фильтр имеет доступ к объекту
    FilterConfig, из которого он может получить параметры инициализации, и ссылку на
    ServletContext. Фильтры настраиваются в дескрипторе развертывания веб-приложения.
    При создании цепочки фильтров, веб-сервер решает, какой фильтр вызывать первым, в соответствии с порядком регистрации фильтров.
    Когда вызывается метод doFilter(...) первого фильтра, веб-сервер создает объект FilterChain,
    представляющий цепочку фильтров, и передает ее в метод.
    Фильтры зависят от контейнера сервлетов, могут работать с js, css.
    Interceptor являются аналогом Filter в Spring. Перехватить запрос клиента можно в трех местах: preHandle, postHandle и afterCompletion.
    Перехватчики работают с HandlerMapping и поэтому должны реализовывать интерфейс
    HandlerInterceptor или наследоваться от готового класса HandlerInterceptorAdapter, после чего переопределить указанные методы.

    Чтобы добавить перехватчики в конфигурацию Spring, необходимо переопределить метод addInterceptors() внутри класса, который реализует WebMvcConfigurer.
    Interceptor основан на механизме Reflection, а фильтр основан на обратном вызове функции.
    preHandle – метод используется для обработки запросов, которые еще не были переданы в метод контроллера. Должен вернуть true для передачи следующему перехватчику или в handler method. False укажет на обработку запроса самим обработчиком и отсутствию необходимости передавать его дальше. Метод имеет возможность выкидывать исключения и пересылать ошибки к представлению.
    postHandle – вызывается после handler method, но до обработки DispatcherServlet для передачи представлению. Может использоваться для добавления параметров в объект
    ModelAndView.
    afterCompletion – вызывается после отрисовки представления.
    Listener – это класс, имплементирующий интерфейс ServletContextListener с аннотацией
    @WebListener. Listener ждет, когда произойдет указанное событие, затем «перехватывает»
    событие и запускает собственное событие. Он инициализируется только один раз при запуске веб-приложения и уничтожается при остановке веб-приложения. Все
    ServletContextListeners уведомляются об инициализации контекста до инициализации любых фильтров или сервлетов в веб-приложении и об уничтожении контекста после того, как все сервлеты и фильтры уничтожены.
    Можно ли передать в запросе один и тот же параметр несколько раз? Как?
    Да, можно принять все значения, используя массив в методе контроллера:
    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 id){...}
    1   ...   17   18   19   20   21   22   23   24   25


    написать администратору сайта