AOP

123 阅读3分钟

spring IOC开发方式 基于注解开发/基于xml开发

spring 用于创建对象的注解 @Componment , @Controller @Service @Repository

spring 用于注入数据的注解 @Value,@Autowired,@Autowired+@Qualifired, @Resource, @Qualifired,@Configuration,@Bean

AOP概述:AOP是面向切面的编程,利用aop可以对业务逻辑各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,提高开发效率

通俗来讲,就是把程序中的重复代码提取出来,在需要执行时 候,使用动态代理的技术,在不修改源码的基础上,对已有方法进行增强

AOP程序设计思想

AOP(面向切面编程)对业务处理过程中的切面进行提取,面对的是处理过程中的莫格步骤或者阶段,获得逻辑过程中的各部分之间的低耦合性的隔离效果。

image.png

从这个图片中可以看出有四个代理对象每个代理对象中分别有四个功能,AOP的作用便是把四个对象中的一些相同的功能拿出来形成新的类

AOP把软件系统分为两个部分:核心关注点和横切关注点

核心关注点:业务处理的主流程

横切关注点:与主流程关系不大但经常发生在核心关注点的多处

AOP的实现方式

配置

配置application文件

<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- Bean definitions go here -->
    
</beans>

image.png

基于xml的实现方式

1.前置通知

<!-- 配置目标类 Bean -->
<bean id="aopService" class="com.xyu.service.impl.AopServiceImpl"/>
<!-- 配置通知 Bean -->
<bean id="loggerUtil" class="com.xyu.util.LoggerUtil"/>
<!-- AOP 配置 -->
<aop:config>
    <!-- 定义一个切面 -->
    <aop:aspect id="logAdvice" ref="loggerUtil">
        <!-- 定义前置通知 -->
        <aop:before method="printLogBefore" pointcut="execution(public void com.xyu.service.impl.AopServiceImpl.performAction())"/>
    </aop:aspect>
</aop:config>
public class demo {
    @Test
    public void methodTest() {
        // 加载 Spring 配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 获取 AopService Bean
        AopService aopService = applicationContext.getBean(AopService.class);
        // 调用目标方法
        aopService.performAction();
    }
}

image.png

2.前置通知方法2

<!-- LoggerUtil bean -->
<bean id="loggerUtil" class="com.xyu.util.LoggerUtil"/>
<!-- AopService bean -->
<bean id="aopService" class="com.xyu.service.impl.AopServiceImpl"/>
<!-- AOP 配置 -->
<aop:config>
    <!-- 定义切入点,匹配所有方法 -->
    <aop:pointcut id="pc1" expression="execution(* *..*.*(..))"/>
    <!-- 定义前置通知 -->
    <aop:aspect id="logAdvice" ref="loggerUtil">
        <aop:before method="printLogBefore" pointcut-ref="pc1"/>
    </aop:aspect>
</aop:config>

image.png

2.xml返回after

<!-- LoggerUtil bean -->
<bean id="loggerUtil" class="com.xyu.util.LoggerUtil"/>
<!-- AopService bean -->
<bean id="aopService" class="com.xyu.service.impl.AopServiceImpl"/>
<!-- AOP 配置 -->
<aop:config>
    <!-- 定义切入点,匹配所有方法 -->
    <aop:pointcut id="pc1" expression="execution(* *..*.*(..))"/>
    <!-- 定义前置通知 -->
    <aop:aspect id="logAdvice" ref="loggerUtil">
        <aop:before method="printLogBefore" pointcut-ref="pc1"/>
        <aop:after-returning method="printLogAfterReturning" pointcut-ref="pc1"/>
    </aop:aspect>
</aop:config>

image.png 3.after-throwing案例联系

<!-- LoggerUtil bean -->
<bean id="loggerUtil" class="com.xyu.util.LoggerUtil"/>
<!-- AopService bean -->
<bean id="aopService" class="com.xyu.service.impl.AopServiceImpl"/>
<!-- AOP 配置 -->
<aop:config>
    <!-- 定义切入点,匹配所有方法 -->
    <aop:pointcut id="pc1" expression="execution(* *..*.*(..))"/>
    <!-- 定义前置通知 -->
    <aop:aspect id="logAdvice" ref="loggerUtil">
        <aop:before method="printLogBefore" pointcut-ref="pc1"/>
        <aop:after-returning method="printLogAfterReturning" pointcut-ref="pc1"/>
        <aop:after-throwing method="printLogAfterthrowing" pointcut-ref="pc1"/>
    </aop:aspect>
</aop:config>

image.png 4.after

<aop:config>
    <!-- 定义切入点,匹配所有方法 -->
    <aop:pointcut id="pc1" expression="execution(* *..*.*(..))"/>
    <!-- 定义前置通知 -->
    <aop:aspect id="logAdvice" ref="loggerUtil">
        <aop:before method="printLogBefore" pointcut-ref="pc1"/>
        <aop:after-returning method="printLogAfterReturning" pointcut-ref="pc1"/>
        <aop:after-throwing method="printLogAfterthrowing" pointcut-ref="pc1"/>
        <aop:after method="printlogafter" pointcut-ref="pc1"/>
    </aop:aspect>
</aop:config>

image.png

public Object printLogAround(ProceedingJoinPoint proceedingJoinPoint) {
    Object result = null;
    try {
        // 获取目标方法的参数
        Object[] args = proceedingJoinPoint.getArgs();

        // 打印前置通知
        System.out.println("printLogAround 环绕通知 前置");

        // 执行目标方法
        result = proceedingJoinPoint.proceed(args);

        // 打印返回后通知
        System.out.println("printLogAround 环绕通知 返回");

        return result;
    } catch (Throwable e) {
        // 异常通知
        System.out.println("printLogAround 环绕通知 异常");
        e.printStackTrace();
        return result;
    } finally {
        // 最终通知
        System.out.println("printLogAround 环绕通知 最终");
    }
}
<bean id="loggerUtil" class="com.xyu.util.LoggerUtil"/>
<!-- AopService bean -->
<bean id="aopService" class="com.xyu.service.impl.AopServiceImpl"/>
<!-- AOP 配置 -->
<aop:config>
    <!-- 定义切入点,匹配所有方法 -->
    <aop:pointcut id="pc1" expression="execution(* *..*.*(..))"/>
    <!-- 定义前置通知 -->
    <aop:aspect id="logAdvice" ref="loggerUtil">
        <aop:before method="printLogBefore" pointcut-ref="pc1"/>
        <aop:after-returning method="printLogAfterReturning" pointcut-ref="pc1"/>
        <aop:after-throwing method="printLogAfterthrowing" pointcut-ref="pc1"/>
        <aop:after method="printlogafter" pointcut-ref="pc1"/>
        <aop:around method="printLogAround" pointcut-ref="pc1"/>
    </aop:aspect>
</aop:config>

image.png

基于注解的开发

image.png

image.png

image.png

image.png

image.png

package com.xyu.util;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;

@Aspect
@Component  // 将切面类注册为 Spring Bean
public class LoggerAnnotationUtil {

    // 前置通知:在目标方法执行之前执行
    @Before("execution(* com.xyu.service.impl.AopServiceImpl.targetMethod(..))")
    public void logBefore() {
        System.out.println("Before method execution: Logging before method execution");
    }

    // 后置通知:在目标方法执行之后执行
    @After("execution(* com.xyu.service.impl.AopServiceImpl.targetMethod(..))")
    public void logAfter() {
        System.out.println("After method execution: Logging after method execution");
    }

    // 环绕通知:可以控制目标方法是否执行,类似于拦截器
    @Around("execution(* com.xyu.service.impl.AopServiceImpl.targetMethod(..))")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Around method execution: Before proceeding");

        // 执行目标方法
        Object result = joinPoint.proceed();

        System.out.println("Around method execution: After proceeding");

        return result;
    }
}