Использование AspectJ весной

задняя часть Spring Шаблоны проектирования
Использование AspectJ весной

Это чистый блог-пример. В Интернете очень мало блогов-примеров об AspectJ. Многие блоги объясняют некоторые концепции АОП-мышления и объясняют AspectJ из самого языка AspectJ, но редактор считает, что это крайне необходимо в проекте. Используйте, другими словами, для начинающих, нет необходимости понимать его из самого языка AspectJ, если вы не понимаете идею АОП, пожалуйста, обратитесь к моему блогуДавайте поговорим о Spring AOP!

Эта статья начнется с применения AspectJ в Spring.

Прежде всего, поймите, что существует множество фреймворков или библиотек для реализации идей АОП. Наиболее известные из них — динамический прокси AspectJ, Cglib и JDK. В конечном итоге все они используют шаблон проектирования прокси. Разница заключается в следующую таблицу:

название Тип агента Фундаментальный характеристика
AspectJ статический прокси Прокси-классы генерируются во время компиляции, но соответствующие аспекты织入в класс прокси
Cglib Динамический прокси Прокси-класс динамически генерируется во время выполнения, а нижний уровень использует структуру обработки байт-кода ASM для преобразования байт-кода и создания новых классов. Чтобы восполнить дефицит, который JDK Dynamic Proxy может только прокси-интерфейсы, CGLIB может динамически прокси-классы
Динамический прокси JDK Динамический прокси Прокси-класс динамически генерируется во время выполнения, а собственный метод вызывается на исходном уровне. только прокси-интерфейсы

Что касается агента cglib, вы можете прочитать другой блог редактора.Использование прокси cglib

1. Использование AspectJ в Spring

1. Включить поддержку аннотации аспекта J в xml

applicationContext.xml

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

2. Объявить класс аспекта

@Aspect
@Component
public class ExecutionAspect {

    @Before("execution(* wokao666.club.myapp.aspectJ.*.before*(..))")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        System.err.println("这是一个前置通知,在方法调用之前被执行!!!");
    }

    @After("execution(* wokao666.club.myapp.aspectJ.*.after*(..))")
    public void doAfter(JoinPoint joinPoint) throws Throwable {
        System.err.println("这是一个后置通知,在方法调用之后被执行!!!");
    }

    @Around("execution(* wokao666.club.myapp.aspectJ.*.around*(..))")
    public void doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.err.println("这是一个环绕通知,在方法调用前后都会执行!!!");
        System.err.println("执行前");
        joinPoint.proceed();
        System.err.println("执行后");
    }
}

Объясните приведенное выше выражение pointcut,executionУказывает тип точки подключения, первая*Представляет перехваченный метод, но возвращает тип значения,*Представляет возвращаемое значение любого типа; вторая частьwokao666.club.myapp.aspectJ.*.before*(..)значит сwokao666.club.myapp.aspectJЛюбой класс в пакете начинается сbeforeметод для начала.

3. Тестовый классMain.java

public class Main {

    private static ClassPathXmlApplicationContext ctx = null;

    public static void main(String[] args) {
    ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    TestMethod test = (TestMethod) ctx.getBean("bean");
    test.before("before");
    System.err.println("=====================================================");
    test.after("after");
    System.err.println("=====================================================");
    test.around("around");
}

4. класс фасоли

@Component("bean")
public class TestMethod {

    public void before(String name) {
        System.err.println("the param Name is " + name);
    }

    public void after(String name) {
        System.err.println("the param Name is " + name);
    }

    public void around(String name) {
        System.err.println("the param Name is " + name);
    }
}

pom.xml

<dependency>
    <groupId>aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.5.4</version>
</dependency>

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.1</version>
</dependency>

Результаты:

这是一个前置通知,在方法调用之前被执行!!!
the param Name is before
=====================================================
the param Name is after
这是一个后置通知,在方法调用之后被执行!!!
=====================================================
这是一个环绕通知,在方法调用前后都会执行!!!
执行前
the param Name is around
执行后

2. Реализация перехвата на основе пользовательских аннотаций

Иногда мы используем пользовательские аннотации для идентификации наших бизнес-методов.Ниже будет объяснена реализация перехвата AspectJ на основе аннотаций.Отличие от необработанных поверхностей - это разница между выражениями pointcut.

1, создайте пользовательскую аннотациюRpcService

/**
 * 远程服务注解,主要用于拦截日志、错误码等方面处理
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = { ElementType.METHOD, ElementType.TYPE })
public @interface RpcService {

}

2. Объявите бизнес-метод

@Component("bean")
public class TestMethod {

	@RpcService
	public void around(String name) {
		System.err.println("the param Name is " + name);
	}
}

3. Объявить класс аспекта

@Aspect
@Component
public class AnnotationAspect {
    @Around("@annotation(wokao666.club.myapp.annotation.RpcService)")
        public void doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.err.println("这是一个环绕通知,在方法调用前后都会执行!!!");
        System.err.println("执行前");
        joinPoint.proceed();
        System.err.println("执行后");
    }
}

4. Тестовый класс

public class Main {

private static ClassPathXmlApplicationContext ctx = null;

    public static void main(String[] args) {
        ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        TestMethod test = (TestMethod) ctx.getBean("bean");
        test.around("around");
    }
}

5. Результаты исполнения

这是一个环绕通知,在方法调用前后都会执行!!!
执行前
the param Name is around
执行后

После окончания, почему вы чувствуете себя немного беспокойно, держитесь крепче!

Если мы хотим получить возвращаемое значение метода cut, мы можем использовать

MethodSignature si = (MethodSignature) joinPoint.getSignature();
System.err.println(si.getReturnType());