【Spring【AOP】】——20、搭建一个AOP测试环境?

在这里插入图片描述

作者简介:zhz小白
公众号:小白的Java进阶之路
专业技能:
1、Java基础,并精通多线程的开发,熟悉JVM原理
2、熟悉Java基础,并精通多线程的开发,熟悉JVM原理,具备⼀定的线上调优经验
3、熟悉MySQL数据库调优,索引原理等,⽇志原理等,并且有出过⼀篇专栏
4、了解计算机⽹络,对TCP协议,滑动窗⼝原理等有⼀定了解
5、熟悉Spring,Spring MVC,Mybatis,阅读过部分Spring源码
6、熟悉SpringCloud Alibaba体系,阅读过Nacos,Sentinel,Seata,Dubbo,Feign,Gateway核⼼源码与设计,⼆次开发能⼒
7、熟悉消息队列(Kafka,RocketMQ)的原理与设计
8、熟悉分库分表ShardingSphere,具有真实⽣产的数据迁移经验
9、熟悉分布式缓存中间件Redis,对其的核⼼数据结构,部署架构,⾼并发问题解决⽅案有⼀定的积累
10、熟悉常⽤设计模式,并运⽤于实践⼯作中
11、了解ElasticSearch,对其核⼼的原理有⼀定的了解
12、了解K8s,Jekins,GitLab
13、了解VUE,GO
14、⽬前有正在利⽤闲暇时间做互游游戏,开发、运维、运营、推销等

本人著作git项目:https://gitee.com/zhouzhz/star-jersey-platform,有兴趣的可以私聊博主一起编写,或者给颗star
领域:对支付(FMS,FUND,PAY),订单(OMS),出行行业等有相关的开发领域
如果此文还不错的话,还请关注、点赞、收藏三连支持一下博主~

文章目录

  • 1、AOP简介
  • 2、作用
  • 3、实现原理
  • 4、优势
  • 5、应用场景
  • 6、AOP相关术语
  • 7、AOP入门实战
    • 7.1、实现AOP打印每个方法结束后打印日志
      • 7.1.1、aop切面类
      • 7.1.2、要被aop的类
      • 7.1.3、MainConfig配置类
      • 7.1.4、测试类
      • 7.1.5、运行结果
  • 8、AOP通知类型
  • 9、AOP切点表达式

1、AOP简介

【Spring【AOP】】——20、搭建一个AOP测试环境?_第1张图片

  • AOP的全称是Aspect Oriented Programming,即面向切面编程。是实现功能统一维护的一种技术,它将业务逻辑的各个部分进行隔离,使开发人员在编写业务逻辑时可以专心于核心业务,从而提高了开发效率。

2、作用

  • 在不修改源码的基础上,对已有方法进行增强。

3、实现原理

  • 动态代理技术。

4、优势

  • 减少重复代码、提高开发效率、维护方便

5、应用场景

  • 事务处理
  • 日志管理
  • 权限控制
  • 异常处理等方面。

6、AOP相关术语

名称 说明
Joinpoint(连接点) 指能被拦截到的点,在Spring中只有方法能被拦截。
Pointcut(切点) 指要对哪些连接点进行拦截,即被增强的方法。
Advice(通知) 指拦截后要做的事情,即切点被拦截后执行的方法。
Aspect(切面) 切点+通知称为切面
Target(目标) 被代理的对象
Proxy(代理) 代理对象
Weaving(织入) 生成代理对象的过程

7、AOP入门实战

  • AspectJ是一个基于Java语言的AOP框架,在Spring框架中建议使用AspectJ实现AOP。

7.1、实现AOP打印每个方法结束后打印日志

7.1.1、aop切面类

package com.zhz.aspect;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;

import java.util.Date;

/**
 * @author zhouhengzhe
 * @date 2022/11/19
 */
@Slf4j
@Aspect
public class AopAspect {

    /**
     * 指定切面的切入点
     */
    @Pointcut("execution(* com.zhz.dao.BookDao.*(..))")
    public void pointCut() {

    }

    /**
     * 前置通知:执行目标方法前 触发
     */
    @Before("pointCut()")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("当前时间为:"+(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"))+",前置通知——方法名:"+joinPoint.getSignature().getName()+",参数:"+JSON.toJSONString(joinPoint.getArgs()));
    }

    /**
     * 后置通知:执行目标方法后触发
     */
    @After(value = "pointCut()")
    public void logAfter(JoinPoint joinPoint) {
        System.out.println("当前时间为:"+(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"))+",后置通知——方法名:"+joinPoint.getSignature().getName()+",参数:"+JSON.toJSONString(joinPoint.getArgs()));

    }

    /**
     * 返回通知:目标方法执行完并返回参数后触发。
     */
    @AfterReturning(value = "pointCut()", returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        System.out.println("当前时间为:"+(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"))+",返回通知——方法名:"+joinPoint.getSignature().getName()+",参数:"+JSON.toJSONString(joinPoint.getArgs())+"返回结果:"+ JSON.toJSONString(result));

    }

    /**
     * 异常通知:目标方法抛出异常后触发
     */
    @AfterThrowing(value = "pointCut()", throwing = "ex")
    public void logAfterThrowing(JoinPoint joinPoint, Exception ex) {
        System.out.println("当前时间为:"+(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"))+",异常通知——方法名:"+joinPoint.getSignature().getName()+",参数:"+JSON.toJSONString(joinPoint.getArgs())+",异常信息:" + ex.getMessage());
    }

    /**
     * 环绕通知,围绕着方法执行
     * 环绕通知需要携带ProceedingJoinPoint类型的参数
     * 环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法。
     * 而且环绕通知必须有返回值,返回值即为目标方法的返回值
     */
    @Around(value = "pointCut()")
    public Object logAround(ProceedingJoinPoint proceedingJoinPoint) {
        System.out.println("当前时间为:"+(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"))+",环绕通知前——方法名:"+proceedingJoinPoint.getSignature().getName()+",参数:"+JSON.toJSONString(proceedingJoinPoint.getArgs()));
        Object result = null;
        //执行目标方法
        try {
            result = proceedingJoinPoint.proceed();
            System.out.println("环绕后");
        } catch (Throwable e) {
            System.out.println("环绕异常后");
            throw new RuntimeException(e);
        }
        return result;
    }
}

7.1.2、要被aop的类

package com.zhz.dao;

import org.springframework.stereotype.Repository;

/**
 * @author zhouhengzhe
 * @description: todo
 * @date 2022/11/4 10:56
 * @since v1
 */
@Repository
public class BookDao {
    public void add(){
        System.out.println("新增图书");
    }

    public void delete(){
        System.out.println("删除图书");
    }

    public void update(){
        System.out.println("更新图书");
    }
}

7.1.3、MainConfig配置类

package com.zhz.config;

import com.zhz.aspect.AopAspect;
import com.zhz.dao.BookDao;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
 * @author zhouhengzhe
 * @description: todo
 * @date 2022/11/4 10:27
 * @since v1
 */
@EnableAspectJAutoProxy
@Configuration
public class MainConfig {

    @Bean
    public BookDao bookDao(){
        return new BookDao();
    }

    // 将切面类加入到容器中
    @Bean
    public AopAspect aopAspect() {
        return new AopAspect();
    }
}

7.1.4、测试类

@Test
public void test4(){
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
    BookDao bean = applicationContext.getBean(BookDao.class);
    bean.add();
    applicationContext.close();
}

7.1.5、运行结果

【Spring【AOP】】——20、搭建一个AOP测试环境?_第2张图片

8、AOP通知类型

通知类型 描述
前置通知 在方法执行前添加功能
后置通知 在方法正常执行后添加功能
异常通知 在方法抛出异常后添加功能
最终通知 无论方法是否抛出异常,都会执行该通知
环绕通知 在方法执行前后添加功能

9、AOP切点表达式

使用AspectJ需要使用切点表达式配置切点位置,写法如下:

  • 标准写法:访问修饰符 返回值 包名.类名.方法名(参数列表)
  • 访问修饰符可以省略。
  • 返回值使用 * 代表任意类型。
  • 包名使用 * 表示任意包,多级包结构要写多个 * ,使用 *… 表示任意包结构
  • 类名和方法名都可以用 * 实现通配
  • 参数列表
    • 基本数据类型直接写类型
    • 引用类型写 包名.类名
    • ***** 表示匹配一个任意类型参数
    • 表示匹配任意类型任意个数的参数
  • 全通配: *** .*(…)**

你可能感兴趣的:(#,Spring,spring,java,后端)