一丶注解和使用说明

Aop一般有以下常用注解:

@Aspect: 该注解是把此类声明为一个切面类

@Before: 该注解是声明此方法为前置通知 (目标方法执行之前就会先执行被此注解标注的方法)

@After: 该注解是声明此方法为后置通知 (目标方法执行完之后就会执行被此注解标注的方法)

@AfterReturning: 该注解是声明此方法为返回通知 (目标方法正常执行返回后就会执行被此注解标注的方法)

@AfterThrowing: 该注解是声明此方法为异常通知 (目标方法在执行出现异常时就会执行被此注解标注的方法)

@Around: 该注解是环绕通知是动态的,可以在前后都设置执行

@PointCut: 该注解是声明一个公用的切入点表达式(通知行为的注解的都可以直接拿来复用)

如果是注解式开发还会用到@EnableAspectJAutoProxy: 该注解是声明这个配置类使用注解式的AOP(还有一种古老的方式是在xml文件里声明开启AOP)

什么时候会用到AOP: 写日志,事务等,就是一些不是业务逻辑代码要做的事就交给AOP来完成。

二丶案例演示AOP的使用

下面一个例子日志输出的功能来演示:

            (1)步骤一:  用maven创建一个项目,pom.xml导入所需的依赖:spring容器依赖,Aop依赖,单元测试依赖。

            (2)步骤二:  创建四个类:  启动配置类:  MyConfig

                                                   业务逻辑类:  MyService

                                                   日志切面类:  MyLog

                                                          测试类:  MyTest

            (3)步骤三:  编写测试代码调式AOP功能怎么实现的

具体步骤分析:

步骤一:  项目搭建

项目搭建好的包级目录如下:

 pom.xml文件的主要依赖项如下:

    <!--单元测试依赖-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter</artifactId>
      <version>RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <!--spring依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.12.RELEASE</version>
    </dependency>
    <!--Aop依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>

步骤二:  写好所需要的类

MyConfig启动配置类如下:

//配置类
@Configuration
@EnableAspectJAutoProxy //开启Aop注解功能
public class MyConfig {

    //向容器中注册: 日子切面类
    @Bean
    public MyLog myLog(){
        return new MyLog();
    }

    //向容器中注册: 业务逻辑类
    @Bean
    public MyService myServie(){
        return new MyService();
    }

}

MyService业务逻辑类如下:

//业务逻辑类
public class MyService {

    //除法方法,返回两个数相除的结果
    public int divide(int a, int b){
        return a / b;
    }

}

MyLog日志切面类如下:

//日志切面类
//得加上此注解此切面类才会生效
@Aspect
public class MyLog {
    
    //抽取公共的切入点表达式
    //该表达式表明MyService类下的所有方法都加上aop功能
    @Pointcut("execution(public int org.com.MyService.*(..))")
    public void pointCut(){};

    //在目标方法之前切入
    //复用上面定义的pointCut()方法上的切入点表达式
    @Before("pointCut()")
    public void logStart(JoinPoint joinPoint){
        //获取目标方法名 (单纯取出来而已下面没有用到这个变量)
        String methodName = joinPoint.getSignature().getName();
        //获取目标方法参数列表 (下面有输出这个)
        Object[] args = joinPoint.getArgs();
        System.out.println("除法运行...参数列表是: {" + Arrays.asList(args) + "}");
    }

    //在目标方法之后切入
    @After("pointCut()")
    public void logEnd(){
        System.out.println("除法结束...");
    }

    //在目标方法正常返回切入
    //result是目标方法正常返回的返回值
    @AfterReturning(value = "pointCut()", returning = "result") 
    public void logReturn(Object result){
        System.out.println("除法正常返回...运行结果: { " + result + " }");
    }
    //在目标方法异常时切入
    //exception是目标方法异常的异常对象
    @AfterThrowing(value = "pointCut()", throwing = "exception") 
    public void logException(Exception exception){
        System.out.println("除法异常...异常信息: {" + exception+ "}");
    }
    
}

测试类: 该类的测试方法未完成,在步骤三来完成并说明最终测试情况

//测试类
public class MyTest {

    //正常测试
    @Test
    public void test01(){}

    //故意传入错误的参数测试(除法运算时分母不能为0,但强行这样做康康会怎么样)
    @Test
    public void test02(){}
    }

}

步骤三:

1:    正常的测试:传入的值都是能正常进行除法运算的,观察控制输出,是不是切面类的前置通知,后置通知,正常返回通知等方法是不是都执行了,测试代码如下:

//正常测试
@Test
public void test01(){
    //通过配置类启动容器
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
    //用id取出业务逻辑类的bean
    MyService myService = (MyService) applicationContext.getBean("myService");
    //调用此bean的divide方法观察控制台的输出信息,其中传入的参数进行除法运算是正常的
    myService.divide(1, 1);
}

控制台输出如下:   

分析:  可见切面类的aop功能真的生效了

2:    异常的测试:故意传一个分母为0这种情况,观察切面类的异常通知方法会不会执行

//故意传入错误的参数测试(除法运算时分母不能为0,但强行这样做康康会怎么样)
@Test
public void test02(){
    //通过配置类启动容器
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
    //用id取出业务逻辑类的bean
    MyService myService = (MyService) applicationContext.getBean("myService");
    //调用此bean的divide方法观察控制台的输出信息,其中传入的分母参数为 0
    try{
        //分母故意传个 0 康康会不会执行切面类的异常通知方法
        myService.divide(1, 0);
    }catch (Exception e){

    }
}

控制台输出如下:

分析:  除法异常,异常通知方法确实执行了!

三丶总结

注解式的Aop就是好用和简单,很多繁琐的事就可以交给Aop来做了,Aop实现的三部曲分别是:

1.  创建业务类。

2.  创建切面类,其中切面类上加@Aspect注解说明该类是个切面类,方法上加上想要的通知功能的注解。

3.  创建配置类,加上@EnableAspectJAutoProxyz注解来开启Aop注解功能,注册之前创建的业务类和切面类。

Logo

Authing 是一款以开发者为中心的全场景身份云产品,集成了所有主流身份认证协议,为企业和开发者提供完善安全的用户认证和访问管理服务

更多推荐