Spring AOP 使用方式

ProxyFactory代理工厂提供了基于切面构造代理对象的能力,Spring框架结合IOC对此进行了一层封装以适应多种场景。封装后为用户提供了一套Spring风格的“API”(使用方式)

1 xml配置方式

引入AOP的schema:

<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.xsd
 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">

1.1 使用aop:aspect标签

定义目标类:

@Slf4j
public class ApplicationRunner {
    public void run() {
        LOGGER.info("exec...");
    }
}


引入增强类:

@Slf4j
public class EnhanceLog {
    public void beforeExec() {
        LOGGER.info("before exec");
    }

    public void afterExec() {
        LOGGER.info("after exec");
    }
}

在xml文件中配置AOP:

<aop:config>
    <aop:pointcut id="runnerExecPc" expression="execution(* *.run(..))"/>
    
    <aop:aspect ref="enhanceLog">
        <aop:before method="beforeExec" pointcut-ref="runnerExecPc"/>
        <aop:after method="afterExec" pointcut-ref="runnerExecPc"/>
    </aop:aspect>
</aop:config>

1.2:使用aop:advisor标签

引入增强类LogAdvice,需要实现org.aopalliance.intercept.MethodInterceptor接口:

@Slf4j
public class LogAdvice implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        LOGGER.info("before intercept exec");
        methodInvocation.proceed();
        LOGGER.info("after intercept exec");
        return null;
    }
}

在xml文件中配置AOP:

    <aop:config>
        <aop:pointcut id="runnerExecPc" expression="execution(* *.run(..))"/>
        <aop:advisor advice-ref="logAdvice" pointcut-ref="runnerExecPc"/>
    </aop:config>

其中:advisor将所有的逻辑都封装在了MethodInterceptor的invoke方法中,通过方法完成增强;aspect通过配置对外展示需要增强逻辑,而不需要实现MethodInterceptor等Advice系列接口。相对而言,aspect的代码侵入性较低。

2 注解方式

Spring通过整合AspectJ为AOP提供了注解形式的使用方式;因此使用注解时,需要添加对aspectjweaver的依赖(由org.aspectj提供)。

2.1 切面注解

@Aspect

注解在类上用于标记切面类;其他注解都可以添加在该类中的方法上。

2.2 增强注解

@Before @After @Around @AfterThrowing @AfterReturing被增强注解的方法内容作为增强。

@Before表示前置增强,@AfterReturing表示后置增强,@Around表示环绕增强,@AfterThrowing表示异常抛出增强,@After表示方法正常执行完或者异常抛出都会执行的增强逻辑;与Spring中定义的增强类型基本保持一致。

被上述注解标注的方法可以增加一个JoinPoint类型(Around为ProceedingJoinPoint类型)的参数(也可不加)用于获取上下文信息;另外,@AfterThrowing还可添加异常类型的参数,而@AfterReturing可以添加一个Object类型的参数(表示运行结果),以下通过案例的形式进行介绍。

添加配置类:

@Configuration
@ComponentScan(basePackages = "org.shangjack.demo.annotation")
@EnableAspectJAutoProxy
public class AopDemoConfiguration {
}

添加目标类:

@Component
@Slf4j
public class DataTask {
    public String syncData() {
        LOGGER.info("start sync data");
        return "success";
    }
}

添加测试用例:

public class Application {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AopDemoConfiguration.class);
        DataTask dataTask = (DataTask)context.getBean("dataTask");
        dataTask.syncData();
    }
}

2.2.1: 前置、后置

切面配置如下所示:

@Component
@Aspect
@Slf4j
public class MyNormalAspect {
    @Before("execution(public String org.shangjack.demo.annotation.DataTask.*(..))")
    public void beforeExec(JoinPoint joinPoint) {
        LOGGER.info("[Before DataTask], joinPoint is {}.", joinPoint);
    }

    @AfterReturning("execution(public String org.shangjack.demo.annotation.DataTask.*(..))")
    public void afterExec(JoinPoint joinPoint) {
        LOGGER.info("[After DataTask], result is {}, joinPoint is {}.", joinPoint);
    }
}

得到如下运行结果:

INF0 org.shangjack.demo.annotation.MyNormalAspect - [Before DataTask], joinPoint is execution(Stri
INF0 org.shangjack.demo.annotation.DataTask-start sync data
INF0 org.shangjack.demo.annotation.MyNormalAspect - [After DataTask],result is execution(String

2.2.2: 环绕通知

在切面中配置环绕增强,如下所示:

@Component
@Aspect
@Slf4j
public class MyAroundAspect {
    @SneakyThrows
    @Around("execution(public String org.shangjack.demo.annotation.DataTask.*(..))")
    public void aroundExec(ProceedingJoinPoint joinPoint) {
        LOGGER.info("[Around DataTask] call before.");
        Object result = joinPoint.proceed();
        LOGGER.info("[Around DataTask] call end, result is {}.", result);
    }
}

得到如下运行结果:

INF0 org.shangjack.demo.annotation.MyAroundAspect - [Around DataTask] call before.
INF0 org.shangjack.demo.annotation.DataTask-start sync data
INF0 org.shangjack.demo.annotation.MyAroundAspect - [Around DataTask] call end, result is success.

2.2.3: 异常抛出增强

在切面中配置异常抛出增强,如下所示:

@Component
@Aspect
@Slf4j
public class MyExceptionAspect {
    @AfterThrowing("execution(public String org.shangjack.demo.annotation.DataTask.*(..))")
    public void afterThrowingExec(JoinPoint joinPoint) {
        LOGGER.info("[AfterThrow DataTask], joinPoint is {}.", joinPoint);
    }
}

得到如下运行结果:

INF0 org.shangjack.demo.annotation.DataTask
start sync data
INF0 org.shangjack.demo.annotation.MyExceptionAspect - [AfterThrow DataTask], joinPoint is execution(String org

3 expression表达式

参考: AspectJ官网 或《AspectJ使用与原理》

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shangjg3

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值