欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【Spring】AOP实现之AspectJ框架

程序员文章站 2022-07-12 14:10:05
...

推荐阅读: 【Spring】AOP详解

AspectJ 框架概述

AspectJ 是基于Java的一个AOP框架,其实现方式比起Java动态代理更为简捷,使用更为方便,而且还支持注解式开发。在Spring中使用AOP开发时,一般推荐使用AspectJ的实现方式。

AspectJ中的通知类型

通知 描述
前置通知 在一个方法执行之前,执行通知。
后置通知 在一个方法执行之后,不考虑其结果,执行通知。
返回后通知 在一个方法执行之后,只有在方法成功完成时,才能执行通知
抛出异常后通知 在一个方法执行之后,只有在方法退出抛出异常时,才能执行通知。
环绕通知 在建议方法调用之前和之后,执行通知。

使用AspectJ实现AOP有两种方式:一种是基于XML的声明式AspectJ,另一种是基于注解的声明式AspectJ

基于XML配置实现

基于XML的声明式AspectJ是指通过XML文件来定义切面、切入点及通知,所有的切面、切入点和通知都必须定义在aop:config元素内。

创建Spring工程

首先创建Spring工程:【Spring】Spring入门案例
pom.xml中加入Spring aopAspectJ相关的包

  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>5.2.7.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>aopalliance</groupId>
      <artifactId>aopalliance</artifactId>
      <version>1.0</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>5.2.7.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.5</version>
    </dependency>

创建目标接口和实现类

public interface UserService {
    public void selectUser();
}
public class UserServiceImpl implements UserService{
    @Override
    public void selectUser() {
        System.out.println("UserServiceImpl -> selectUser");
    }
}

创建切面类

package com.lucas;


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class MyAspect {
    //前置通知
    public void myBefore(JoinPoint joinPoint){
        System.out.println("MyAspect ->前置通知:"+joinPoint);
        System.out.println("MyAspect ->前被植入增强处理的目标方法:"+joinPoint.getSignature().getName());
    }
    //后置通知
    public void myAfterReturrning(JoinPoint joinPoint, Object ret){
        System.out.println("MyAspect ->前后置通知:"+joinPoint);
        System.out.println("MyAspect ->前被植入增强处理的目标方法:"+joinPoint.getSignature().getName() +" ret =" +ret);
    }
    /*
     * 环绕通知
     * proceedingJoinPoint是JoinPoint子接口,表示可以执行目标方法
     * 1.必须是Object类型的返回值
     * 2.必须接收一个参数,类型为ProceedingJoinPoint
     * 3.必须throws Throwable
     */
    public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        System.out.println("MyAspect ->前环绕前通知");
        //执行当前目标方法
        Object obj = proceedingJoinPoint.proceed();
        System.out.println("MyAspect ->前环绕后通知");
        return obj;
    }
    //异常通知
    public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
        System.out.println("MyAspect ->前异常通知:"+e.getMessage());
    }
    //最终通知
    public void myAfter(){
        System.out.println("MyAspect ->前最终通知");
    }
}

Spring配置文件

<?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.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 目标类 -->
    <bean id="userService" class="com.lucas.UserServiceImpl"></bean>
    <!-- 切面 -->
    <bean id="myAspect" class="com.lucas.MyAspect"></bean>
    <aop:config>
        <!-- 配置切面 -->
        <aop:aspect ref="myAspect">
            <!-- 配置切入点 -->
            <aop:pointcut expression="execution(* com.lucas.*.*(..))" id="myPointCut"/>
            <!-- 前置通知 -->
            <aop:before method="myBefore" pointcut-ref="myPointCut"/>
            <!-- 后置通知      returning属性:用于设置后置通知的第二个参数的名称,类型是Object -->
            <aop:after-returning method="myAfterReturrning" pointcut-ref="myPointCut" returning="ret"/>
            <!-- 环绕通知 -->
            <aop:around method="myAround" pointcut-ref="myPointCut"/>
            <!-- 异常通知:如果没有异常,将不会执行增强
                 throwing属性:用于设置通知第二个参数的的名称、类型-->
            <aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="e"/>
            <!-- 最终通知 -->
            <aop:after method="myAfter" pointcut-ref="myPointCut"/>
        </aop:aspect>
    </aop:config>
</beans>

测试代码和运行结果

public class App {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new
                ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService) applicationContext.getBean("userService");
        userService.selectUser();
    }
}

【Spring】AOP实现之AspectJ框架

基于注解实现

目标接口和实现类

public interface UserService {
    public void selectUser();
}
@Service("userService")
public class UserServiceImpl implements UserService {
    @Override
    public void selectUser() {
        System.out.println("UserServiceImpl -> selectUser");
    }
}

切面类

package com.lucas;


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class MyAspect {
    @Pointcut("execution(* com.lucas.*.*(..))")
    public void myPointCut() {

    }

    //前置通知
    @Before("myPointCut()") //注解里面的值为上面的方法名
    public void myBefore(JoinPoint joinPoint){
        System.out.println("MyAspect ->前置通知:"+joinPoint);
        System.out.println("MyAspect ->前被植入增强处理的目标方法:"+joinPoint.getSignature().getName());
    }
    //后置通知
    @AfterReturning(value = "myPointCut()", returning = "ret")
    public void myAfterReturrning(JoinPoint joinPoint, Object ret){
        System.out.println("MyAspect ->前后置通知:"+joinPoint);
        System.out.println("MyAspect ->前被植入增强处理的目标方法:"+joinPoint.getSignature().getName() +" ret =" +ret);
    }
    /*
     * 环绕通知
     * proceedingJoinPoint是JoinPoint子接口,表示可以执行目标方法
     * 1.必须是Object类型的返回值
     * 2.必须接收一个参数,类型为ProceedingJoinPoint
     * 3.必须throws Throwable
     */
    @Around("myPointCut()")
    public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        System.out.println("MyAspect ->前环绕前通知");
        //执行当前目标方法
        Object obj = proceedingJoinPoint.proceed();
        System.out.println("MyAspect ->前环绕后通知");
        return obj;
    }
    //异常通知
    @AfterThrowing(value = "myPointCut()", throwing = "e")
    public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
        System.out.println("MyAspect ->前异常通知:"+e.getMessage());
    }
    //最终通知
    @After("myPointCut()")
    public void myAfter(){
        System.out.println("MyAspect ->前最终通知");
    }
}

Spring配置文件

<?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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="com.lucas"/>
    <!--    开启AspectJ 注解的支持-->
    <aop:aspectj-autoproxy/>
</beans>

测试代码

public class App {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new
                ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService) applicationContext.getBean("userService");
        userService.selectUser();
    }
}

运行结果:
【Spring】AOP实现之AspectJ框架