Энди прав со всем, что он сказал. Поскольку вы, похоже, новичок в AspectJ, а также Java, я немного переработал ваш пример кода, чтобы помочь вам начать работу. Вещи, которые я заметил на этом пути:
- Вы используете очень старую версию AspectJ 1.6.10. Это с 2010 года и даже не последняя версия 1.6 (которая будет 1,6.12). Как насчет использования текущей версии AspectJ 1.8.6?
- Я чистый парень кода и заметил, что ваши имена классов довольно запутывают то, что вы хотите продемонстрировать с помощью образца кода.Так что я переименовал их:
Test
→ Application
TestAspect
→ Helper
AspectTest
→ MyAnnotation
AspectJTest
→ MethodInterceptor
- Я также изменил типы Возвратите
Helper
методы, чтобы вернуть что-то кроме void
для демон укажите следующий вопрос.
- Ваш
@Around
совет имеет тип возврата void
. Таким образом, он не работает, если pointcut попадает в непустой метод. Я изменил тип возврата на Object
и код, чтобы вернуть результат proceed()
, чтобы показать, как это можно сделать более общим образом.
- Ваш совет
@Around
всегда регистрирует одно и то же сообщение. Я обновил его, чтобы зарегистрировать фактическую информацию о соединении (до и после вызова proceed()
), чтобы мы могли видеть, что происходит в журнале консоли.
- Как сказал Энди, очевидно, что вы планируете использовать аннотацию, чтобы соответствовать аннотированным методам с помощью pointcut. Таким образом, я изменил область хранения на
RUNTIME
.
- Ваша pointcut предназначена для всех методов, включая
Application.main
и . Я изменил pointcut только на целевые методы, либо несущие @MyAnnotation
, либо подстроку «Aspect» в имени своего метода.
- Кажется, что вы хотите просмотреть время выполнения метода и сравнить методы с аспектами, применяемыми к методам, не ориентированным на аспекты. Вместо создания большого количества экземпляров
Date
и вызова new Date().getTime()
(возвращает миллисекунды) вы можете просто использовать System.nanoTime()
(возвращает наносекунды).
- При профилировании вы хотите измерить время выполнения метода, а не время создания объекта. Таким образом, я изменил код, чтобы просто создать один экземпляр
Helper
, который затем повторно используется во всем методе main
.
- Класс
Application
не нуждается в пустом конструкторе по умолчанию, поскольку он автоматически генерируется JVM.
- Чтобы получить значимые результаты профилирования, вы должны использовать большее количество повторений (например, миллион). Я представил константу с именем
LOOP_COUNT
, чтобы упростить это для всех трех циклов.
- Внимание! Если вы хотите измерить время выполнения метода, вы не должны печатать что-либо в своем аспекте, потому что тогда вы также будете измерять время, необходимое для записи чего-либо на консоль. Таким образом, я прокомментировал заявления печати в этом аспекте. Вы можете активировать их для меньшего количества повторений, чтобы увидеть, что происходит.
рефакторинга код:
package oata;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(value = ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {}
package oata;
import oata.MyAnnotation;
public class Helper {
public double doItWithout(int i) {
return Math.acos(i);
}
@MyAnnotation
public double doItAnnotated(int i) {
return Math.acos(i);
}
public double doItAspect(int i) {
return Math.acos(i);
}
}
package oata;
public class Application {
private static final int LOOP_COUNT = 100000000;
public static void main(String arg[]) {
Helper helper = new Helper();
System.out.printf(
"Profiling statistics for %,d repetitions%n%n",
LOOP_COUNT
);
long startTime = System.nanoTime();
for (int i = 0; i < LOOP_COUNT; i++)
helper.doItWithout(i);
System.out.printf(
"Method not targeted by aspect:%n %,15d ns%n",
System.nanoTime() - startTime
);
startTime = System.nanoTime();
for (int i = 0; i < LOOP_COUNT; i++)
helper.doItAnnotated(i);
System.out.printf(
"Method targeted by aspect because it is annotated:%n %,15d ns%n",
System.nanoTime() - startTime
);
startTime = System.nanoTime();
for (int i = 0; i < LOOP_COUNT; i++)
helper.doItAspect(i);
System.out.printf(
"Method targeted by aspect because of its name:%n %,15d ns%n",
System.nanoTime() - startTime
);
}
}
package oata.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class MethodInterceptor {
@Around("execution(@oata.MyAnnotation * *(..)) || execution(* *Aspect*(..))")
public Object around(ProceedingJoinPoint jp) throws Throwable {
// System.out.println("BEFORE " + jp);
Object result = jp.proceed();
// System.out.println("AFTER " + jp);
return result;
}
}
Образец журнала консоли для 1 повторения с операторами аспект журнала включено:
Profiling statistics for 1 repetitions
Method not targeted by aspect:
153.893 ns
BEFORE execution(double oata.Helper.doItAnnotated(int))
AFTER execution(double oata.Helper.doItAnnotated(int))
Method targeted by aspect because it is annotated:
3.102.128 ns
BEFORE execution(double oata.Helper.doItAspect(int))
AFTER execution(double oata.Helper.doItAspect(int))
Method targeted by aspect because of its name:
55.295 ns
Как вы можете видеть здесь, результаты не очень убедительны только с одним вызовом на метод.
Образец журнала консоли для 100.000.000 (сто миллионов) повторы с утверждениями аспект журнала отключенными:
Profiling statistics for 100.000.000 repetitions
Method not targeted by aspect:
843.407.034 ns
Method targeted by aspect because it is annotated:
1.219.571.173 ns
Method targeted by aspect because of its name:
1.175.436.574 ns
Теперь результат более убедительным: метод не нацелен на какой-либо аспект выполняется быстрее, чем следующие два метода, которые имеют примерно равное время выполнения 1,2 секунды, что следовало ожидать, потому что используемые точки могут быть определены статически во время компиляции (для CTW) или времени ткачества (для LTW).
Я изменил тему, чтобы отразить то, что вы просите. В частности, я удалил часть «в приложении non-Spring», потому что AspectJ абсолютно не зависит от Spring, так что не стоит упоминать об этом. Использование его в дополнение к или вместо Spring AOP из Spring - скорее специальность, а не обычный случай. – kriegaex