Статьи

Аспектно-ориентированное программирование с Spring AspectJ и Maven

Spring Framework поставляется с поддержкой AOP . На самом деле, как указано в справочной документации Spring ,

« Одним из ключевых компонентов Spring является AOP Framework. Хотя контейнер Spring IoC не зависит от AOP, а это означает, что вам не нужно использовать AOP, если вы этого не хотите, AOP дополняет Spring IoC, предоставляя очень функциональное промежуточное решение. АОП используется в Spring Framework для…

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

Тем не менее, среда Spring AOP имеет определенные ограничения по сравнению с полной реализацией AOP , такой как AspectJ . Наиболее распространенные проблемы, с которыми люди сталкиваются при работе со средой Spring AOP, связаны с тем, что Spring AOP «основан на прокси». Другими словами, когда bean-компонент используется в качестве зависимости и его метод (ы) должен указываться конкретным аспектом (ами), контейнер IoC внедряет прокси-компонент bean с учетом аспекта вместо самого bean-компонента. Вызовы метода выполняются для экземпляра прокси-компонента, прозрачного для пользователя, для того, чтобы логика аспекта выполнялась до и / или после делегирования вызова фактическому компоненту «proxy-ed».

Кроме того, среда Spring AOP использует динамические прокси JDK или CGLIB для создания прокси для данного целевого объекта. Первый может создавать прокси только для интерфейсов, а второй — для прокси конкретных классов, но с некоторыми ограничениями. В частности, как указано в справочной документации Spring ,

« Если целевой объект для прокси реализует хотя бы один интерфейс, то будет использоваться динамический прокси JDK. Все интерфейсы, реализованные целевым типом, будут проксированы. Если целевой объект не реализует никаких интерфейсов, будет создан прокси-сервер CGLIB. »

Подводя итог, при работе со средой Spring AOP необходимо учитывать две важные вещи:

  1. Если ваш компонент «proxy-ed» реализует хотя бы один интерфейс, прокси-компонент может быть ТОЛЬКО приведен к этому интерфейсу (ам). Если вы попытаетесь привести его к классу bean-компонента «proxy-ed», вы должны ожидать, что ClassCastException будет генерироваться во время выполнения. Тем не менее, среда Spring AOP предоставляет возможность принудительно использовать прокси CGLIB, но с вышеупомянутыми ограничениями (см. Соответствующую главу справочной документации Spring )
  2. Аспекты не относятся к внутриоперационным вызовам. Это означает, что прокси не может перехватить вызов метода, происходящего из другого метода того же компонента «proxy-ed»

Наша рекомендация по преодолению вышеуказанных проблем заключается в использовании AspectJ ткачества. Другими словами, вводить аспектную логику непосредственно в целевой класс и устранять необходимость проксировать все методы. Есть три способа ввести инструкции, подразумеваемые аспектами AspectJ :

  1. время компиляции — компиляция целевого исходного кода или классов аспектов с помощью компилятора AspectJ
  2. пост компиляции — вставка инструкций аспекта в уже скомпилированные классы
  3. время загрузки — вставка инструкций аспекта в байт-код во время загрузки класса

Можно использовать любой из упомянутых выше подходов. В этом уроке мы расскажем, как использовать ткачество времени компиляции AspectJ в Spring и Maven . Мы собираемся реализовать минимальный «приветственный» Spring сервис и соответствующий «приветственный» аспект AspectJ . Вызовы методов службы Spring будут перехватываться аспектом AspectJ . Аспект AspectJ обогатит сообщение приветствия службы Spring своим собственным сообщением приветствия. «Приветственное» сообщение аспекта AspectJ будет внедрено из контейнера Spring , просто чтобы показать, как вы можете внедрить зависимости Spring в аспекты AspectJ .

Пользователи Spring , которые уже реализовали аспекты для своих сервисов bean-компонентов, могут прозрачно переключаться на AspectJ , что означает, что не требуется писать специальный код, поскольку среда Spring AOP использует подмножество языка выражений AspectJ pointcut, а аспекты @AspectJ Spring полностью подходят для ткачества AspectJ. ,

Нашей предпочтительной средой разработки является Eclipse , поэтому в качестве предварительного условия у вас должна быть установлена Eclipse с поддержкой Maven . Установка плагина Maven для Eclipse выходит за рамки данного руководства и не будет обсуждаться. Тем не менее вам понадобятся следующие компоненты:

  1. Затмение отсюда
  2. Плагин Maven для Eclipse отсюда

Для этого урока мы будем использовать Eclipse Galileo, «m2eclipse» Maven Integration для Eclipse Plugin версии 0.10.0, Spring версии 3.0.1, aspectjrt версии 1.6.7 и aspectj-maven-plugin версии 1.3.

Давайте начнем,

  1. Создать новый проект Maven, перейти к файлу? Проект? Мавен? Maven Project
  2. На странице мастера «Выберите имя проекта и местоположение» убедитесь, что опция «Создать простой проект (пропустить выбор архетипа») не отмечена, нажмите «Далее», чтобы продолжить со значениями по умолчанию.
  3. На странице мастера «Выберите архетип» выберите «Индексатор Nexus» в раскрывающемся списке «Каталог», а после обновления области выбора архетипов выберите архетип «webapp-jee5» из файла org.codehaus.mojo. Архетипы «использовать. Вы можете использовать текстовое поле «фильтр», чтобы сузить результаты поиска. Нажмите «Далее», чтобы продолжить
  4. На странице мастера «Введите идентификатор артефакта» вы можете указать название и основной пакет вашего проекта. Мы установим переменную «Group Id» в «com.javacodegeeks», а переменную «Artifact Id» в «aspectjspring». Вышеупомянутые выборы составляют основной пакет проекта как «com.javacodegeeks.aspectjspring» и имя проекта как «aspectjspring». Нажмите «Готово», чтобы выйти из мастера и создать свой проект.

Давайте вспомним несколько вещей о структуре веб-проекта Maven.

  1. Папка / src / main / java содержит исходные файлы для динамического содержимого приложения
  2. Папка / src / test / java содержит все исходные файлы для модульных тестов
  3. Папка / src / main / webapp содержит необходимые файлы для создания допустимого веб-приложения, например, «web.xml»
  4. Папка / target содержит скомпилированные и упакованные результаты
  5. «Pom.xml» — это файл объектной модели проекта (POM). Единственный файл, который содержит все связанные с проектом конфигурации.

Чтобы правильно использовать Spring во время выполнения, мы должны предоставить все необходимые библиотеки для веб-приложения. Откройте графический редактор вашего «pom.xml» и внесите следующие изменения:

  1. Найдите раздел «Свойства» на странице «Обзор» редактора POM и внесите следующие изменения:
  • Создайте новое свойство с именем org.springframework.version и значением 3.0.1.RELEASE
    • Создайте новое свойство с именем maven.compiler.source и значением в соответствии с версией вашей среды выполнения Java, мы будем использовать 1.6
      • Создайте новое свойство с именем maven.compiler.target и значением в соответствии с версией вашей среды выполнения Java, мы будем использовать 1.6
      1. Перейдите на страницу «Зависимости» редактора POM и создайте следующие зависимости (вы должны заполнить поля «GroupId», «Artifact Id» и «Version» в разделе «Dependency Details» на этой странице):
        • Идентификатор группы: org.springframework Идентификатор артефакта: spring-web Версия: $ {org.springframework.version}
          • Идентификатор группы: org.aspectj Идентификатор артефакта: aspectjrt Версия: 1.6.7
          1. Перейдите на страницу «Плагины» редактора POM и создайте следующий плагин (вы должны заполнить поля «GroupId», «Artifact Id» и «Version» раздела «Сведения о плагине» на этой странице):
            • Идентификатор группы: org.codehaus.mojo Идентификатор артефакта: aspectj-maven-plugin Версия: 1.3
            1. На странице «Плагины» редактора POM выберите только что созданный плагин (из раздела «Плагины») и свяжите его с целью выполнения компиляции. Для этого найдите раздел «Выполнение» и создайте новое выполнение. В разделе «Сведения о выполнении» создайте новую цель и назовите ее « compile »
            2. Вновь созданному плагину требуется одно окончательное изменение конфигурации. Мы должны определить, какую версию среды выполнения Java мы используем, чтобы компилятор AspectJ правильно создавал классы аспектов. Нам нужно отредактировать файл «pom.xml», чтобы внести изменения. Выберите страницу «pom.xml» редактора POM, найдите вновь созданный плагин и измените его следующим образом:
            3. 01
              02
              03
              04
              05
              06
              07
              08
              09
              10
              11
              12
              13
              14
              15
              16
              <plugin>
               <groupId>org.codehaus.mojo</groupId>
               <artifactId>aspectj-maven-plugin</artifactId>
               <version>1.3</version>
               <configuration>
                <source>${maven.compiler.source}</source>
                <target>${maven.compiler.target}</target>
               </configuration>
               <executions>
                <execution>
                 <goals>
                  <goal>compile</goal>
                 </goals>
                </execution>
               </executions>
              </plugin>
            4. Наконец, измените «maven-compiler-plugin», как показано ниже:
            5. 1
              2
              3
              4
              5
              6
              7
              8
              9
              <plugin>
               <groupId>org.apache.maven.plugins</groupId>
               <artifactId>maven-compiler-plugin</artifactId>
               <version>2.0.2</version>
               <configuration>
                <source>${maven.compiler.source}</source>
                <target>${maven.compiler.target}</target>
               </configuration>
              </plugin>

              Как видите, Maven декларативно управляет библиотечными зависимостями. Создается локальный репозиторий (по умолчанию в папке {user_home} /. M2), и все необходимые библиотеки загружаются и помещаются туда из общедоступных репозиториев. Кроме того, внутрибиблиотечные зависимости автоматически разрешаются и обрабатываются.

              Следующим шагом является предоставление хуков для веб-приложения для загрузки контекста Spring при запуске.

              Найдите файл «web.xml» в / src / main / webapp / WEB-INF и добавьте следующее:

              Для загрузки контекста Spring при запуске,

              1
              2
              3
              4
              5
              <listener>
               <listener-class>
                org.springframework.web.context.ContextLoaderListener
               </listener-class>
              </listener>

              Теперь давайте создадим файл applicationContext.xml, который будет управлять контейнером Spring . Создайте файл в каталоге / src / main / webapp / WEB-INF. Пример «applicationContext.xml» представлен ниже

              Что следует отметить здесь:

              1. Измените атрибут base-package элемента context: component-scan на тот, который является базовым пакетом вашего проекта, чтобы проверять его на наличие компонентов Spring.
              2. Мы должны определить наши аспекты в «applicationContext.xml», только если мы хотим внедрить в них зависимости
              3. AspectJ обозначает термин «аспектная ассоциация». Он определяет, как управлять состоянием аспекта. Поддерживаются следующие государственные ассоциации:
              • Для JVM — создается и используется один экземпляр общего аспекта (по умолчанию)
              • Для объекта — аспект имеет свое состояние для каждого рекомендованного объекта.
              • Для каждого потока управления — аспект имеет свое собственное состояние для конкретного потока управления
                Все классы аспектов AspectJ имеют статические методы hasAspect () и aspectOf (). Эти методы неявно генерируются компилятором / ткачом AspectJ . Таким образом, для стандартного состояния аспекта существует один экземпляр аспекта, который можно получить с помощью метода aspectOf ()

              Давайте теперь создадим сервис Spring приветствия и соответствующий аспект AspectJ приветствия. Создайте подпакет с именем «services» в вашем основном пакете и поместите туда класс «GreetingService». Пример услуги «приветствие» показан ниже:

              01
              02
              03
              04
              05
              06
              07
              08
              09
              10
              11
              12
              package com.javacodegeeks.aspectjspring.services;
               
              import org.springframework.stereotype.Service;
               
              @Service("greetingService")
              public class GreetingService {
               
               public String sayHello() {
                return "Hello from Greeting Service";
               }
                
              }

              Создайте подпакет под названием «аспекты» под вашим основным пакетом и поместите туда класс «GreetingAspect». Пример «приветствия» показан ниже:

              01
              02
              03
              04
              05
              06
              07
              08
              09
              10
              11
              12
              13
              14
              15
              16
              17
              18
              19
              20
              21
              22
              package com.javacodegeeks.aspectjspring.aspects;
               
              import org.aspectj.lang.ProceedingJoinPoint;
              import org.aspectj.lang.annotation.Around;
              import org.aspectj.lang.annotation.Aspect;
               
              @Aspect
              public class GreetingAspect {
               
               private String message;
               
               public void setMessage(String message) {
                this.message = message;
               }
               
               @Around("execution(* com.javacodegeeks.aspectjspring.services.GreetingService.*(..))")
               public Object advice(ProceedingJoinPoint pjp) throws Throwable {
                String serviceGreeting = (String) pjp.proceed();
                return message + " and " + serviceGreeting;
               }
                
              }

              Наконец, найдите главную веб-страницу вашего проекта, «index.jsp», в папке / src / main / webapp и измените ее следующим образом:

              01
              02
              03
              04
              05
              06
              07
              08
              09
              10
              11
              12
              13
              14
              15
              16
              17
              18
              <%@ page language="java" import="org.springframework.web.context.WebApplicationContext, org.springframework.web.context.support.WebApplicationContextUtils, com.javacodegeeks.aspectjspring.services.GreetingService"%>
              <%@page contentType="text/html" pageEncoding="UTF-8"%>
              <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
               
              <%
              WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
              GreetingService greetingService = (GreetingService) webApplicationContext.getBean("greetingService");
              %>
              <html>
                  <head>
                      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
                      <title>JSP Page</title>
                  </head>
                  <body>
                      <h1>Test service invoked and greets you by saying : <%=greetingService.sayHello()%></h1>
                  </body>
              </html>

              Что следует отметить здесь:

              1. После загрузки страницы мы извлекаем контекст веб-приложения Spring и ищем наш «приветствующий» сервис. Все, что нам нужно сделать, это вызвать метод «sayHello ()», чтобы увидеть объединенное приветственное сообщение с нашей стороны и сервиса

              Чтобы создать приложение, щелкните правой кнопкой мыши на вашем проекте? Беги как ? Maven пакет

              Для развертывания веб-приложения просто скопируйте файл «.war» из каталога «target» в папку Apache — Tomcat «webapps».

              Для запуска приложения укажите ваш браузер по следующему адресу

              HTTP: // локальный: 8080 / {application_name} /

              Если все прошло хорошо, вы должны увидеть на своей главной веб-странице следующее:

              «Тестовый сервис вызывается и приветствует вас, говоря:« Привет из аспекта приветствия »и« Привет из службы приветствия »»

              Вы можете скачать проект здесь

              Надеюсь, вам понравилось

              Джастин

              Статьи по Теме :