Java

       

Аудит


Реализации аудита могут существенно отличаться, например можно фиксировать каждый вызванный «контроллер» с помощью добавления в каждый метод контроллера вызова метода записи в журнал. Или можно отслеживать посетителей и их путь по сайту с помощью сессии и специального фильтра (такой подход реализован в  ) но возникает проблема установления соответствия между выполнением бизнес-логики и URL на сайте. В любом случае вызовы системы аудита распределяются по всему коду системы, и тем самым существенно затрудняют сопровождение системы и её эволюцию.


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

Красота АОП решения в том, что сквозная функциональность аудита изолирована в пределах аспекта. Все изменения в типе и детализации событий могут быть с лёгкостью проведены не затрагивая основную функциональность.

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

Создадим новый аспект, с pointcut перехватывающий все выполнения контроллеров, и захватывающий объект запроса. После чего на основе созданного pointcut, напишем before advice выводящий сообщение на System.out.

Код аспекта:

package aop.example;

import org.aspectj.lang.*; import javax.servlet.http.*;

/** * Аспект обеспечивающий аудит * @author Zubairov Renat */ public aspect AuditAspect {

/** * Все методы которые необходимо
заносить в журнал * Так же собираем запрос
для извлечения от туда сесии */ public pointcut controllerMethods
(HttpServletRequest request) : // Выполнение всех методов
параметрами которых являются HttpServletRequest
и HttpServletResponse // для всех классов наследников
HttpServlet execution(* javax.servlet.http.
HttpServlet+.*(HttpServletRequest,
HttpServletResponse)) && args(request,
HttpServletResponse);

/** * Advice который обеспечивает печать
на стандартный вывод * информации какой метод будет
выполнен и пользователь * который выполняет метод */ before(HttpServletRequest request)
: controllerMethods(request) { // Собираем статическую информацию
о точке вплетения Signature sig = thisJoinPointStaticPart.
getSignature(); // Выводим доступную информацию System.out.println("User " + request.getSession().getAttribute
(EntranceFilter.USER_KEY).toString() + " executing " + sig.
getDeclaringType().getName() + "." + sig.getName()); }

}

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

В нашем примере стандартный вывод системы будет отображать строки вида:

User Anonymous executing aop.example.LoginServlet.doGet

User user1 executing aop.example.ViewServlet.doGet



Содержание раздела