SPRING-SOURCE.RU

Добавление Аспектно-ориентированного программирования в приложение

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

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

Добавляем Logging Aspect (аспект логирования)

В этой части, вы сможете попробовать Spring AOP, применив аспект логирования к уже существующему приложению — Calculation.

Код для аспекта:

                        
package com.wrox.begspring.aspects; 
import org.aspectj.lang.JoinPoint; 
import org.aspectj.lang.annotation.Aspect; 
import org.aspectj.lang.annotation.Before; 
@Aspect 
public class LoggingAspect {  
  @Before("execution(* com.wrox.begspring.Operation.*(..))") 
  public void logMethodExecution(JoinPoint jp) { 
    System.out.println("AOP logging -> " 
        + jp.toShortString() ); 
  }  
} 
		

Аспект логирования, который будет применяться выделен жирным цветом. Запомните, что никто не знает об этом коде аспекта, который ссылается на CalculateSpring код — цель к которой он применяется. В действительности, этот аспект может быть отредактирован независимо от CalculateSpring кода.

Этот код выводит сообщение, похожее на следующее, всякий раз, когда вызывается метод Operation в интерфейсе. Вызов происходит из CalculateSpring кода. Результат вызова:

AOP logging -> execution(getOpsName)
		

Давайте попробуем

  1. Заходим в директорию springaop проекта
  2. Компилируем проект, используя Maven 2
    mvn compile
  3. Запускаем код, используя Maven 2
    mvn exec:java -Dexec.mainClass=com.wrox.begspring.CalculateSpringAOP–Dexec.args="3000 3"
  4. Смотрим на результат выполнения:
    AOP logging -> execution(getOpsName)
    AOP logging -> execution(operate)
    The result of 3000 times 3 is 9000!

Обратите внимание, что запуск двух методов getOpsName() и operate() из интерфейса, вызывает логирование. Еще, реализация интерфейсов - таких как OpAdd и OpMultiply - не логируются вовсе.

Как это работает

Главный код для CalculateSpring переименован в CalculateSpringAOP, и показан здесь:

package com.wrox.begspring;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class CalculateSpringAOP {
  private Operation ops;
  private ResultWriter wtr;
public void setOps(Operation ops) {
 this.ops = ops;
}
public void setWriter(ResultWriter writer) {
 wtr = writer;
}
public static void main(String[] args) {
  ApplicationContext context =
    new ClassPathXmlApplicationContext(
          "beans.xml");
  BeanFactory factory = (BeanFactory) context;
  CalculateSpringAOP calc =
    (CalculateSpringAOP) factory.getBean("opsbean");
  calc.execute(args);
}


  public void execute(String [] args) {
    long op1 = Long.parseLong(args[0]);
    long op2 = Long.parseLong(args[1]);
       wtr.showResult("The result of " + op1 +
           ops.getOpsName() + op2 + " is "
           + ops.operate(op1, op2) + "!");
  }
}
		

Обратите внимание, что этот главный код вообще не модифицируется. Аспект примененный через SpringAOP не требует внесения перемен в тело целевого кода.

Связывание в AOP прокси

Как и другие Spring техники, АОП связывает через конфигурационный файл (описание контекста). Если посмотреть в beans.xml файл, можно увидеть, как именно применяется аспект.

<?xml version=”1.0” encoding=”UTF-8”?>
<beans xmlns=”http://www.springframework.org/schema/beans”
       xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
       xmlns:aop=”http://www.springframework.org/schema/aop”
       xsi:schemaLocation=”http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
        http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-2.0.xsd”>
	   <bean id=”screen” class=”com.wrox.begspring.ScreenWriter” />
	   <bean id=”multiply” class=”com.wrox.begspring.OpMultiply” />
	   <bean id=”opsbean” class=”com.wrox.begspring.CalculateSpringAOP”
	   autowire=”byType”/>
	    <aop:aspectj-autoproxy/>
	   <bean id=”logaspect” class=”com.wrox.begspring.aspects.LoggingAspect”/>
	   </beans>
		

Spring контейнер обрабатывает элемент <aop:aspectj-autoproxy> и автоматически создает динамический прокси, необходимый для АОП когда он связывает бины вместе. Прокси автоматически добавляются Spring-ом к CaculateSpringAOP классу.

В этом случае, Spring 2 использует AspectJ pointcut язык (будет описываться в следующих секциях).

Соответствие JointPoints через AspectJ Pointcut выражения

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

package com.wrox.begspring.aspects;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class LoggingAspect {
  @Before(“execution(* com.wrox.begspring.Operation.*(..))”)
  public void logMethodExecution(JoinPoint jp) {
    System.out.println(“AOP logging -> “
        + jp.toShortString() );
  }
}
		

@Aspect аннотация выделяет этот класс как аспект. @Before аннотация определяет текущую pointcut. Это выражение говорит, Примени этот аспект перед тем, как ты вызовешь любой метод типа com.wrox.begspring.Operation.

Com.wrox.begspring.Operation - это интерфейс и результат в аспекте будет всегда выводиться перед запуском метода c любой реализацией этого интерфейса.

Аргумент у метода logMethodExecution() - это join point. В нашем случае мы вызываем toShortString(), а вообще у join point существует немного больше методов. Здесь описывать мы их не станем.

Aspect - это java класс и мы можем определять их сколько угодно. Теперь мы можем соединять аспекты логирования, которые разделены между собой, можем гибко применять их к большому количеству кода через манипулирование pointcut выражениями. Это суть того, как АОП может оказаться полезным в повседневной работе программиста.