AOP-AspectJ 切面技术及使用MethodInterceptor实现切面

news2024/11/27 20:33:02

目录

一、简介

二、什么是AspectJ

AOP 思想概述

AOP 实现方式

AOP 特性概念

切点指示器 

 通知类型

三、实现AOP的方式

四、配置说明

自定义注解作为切点

 NeedCut 

 MyAop 

 GirlController 

继承MethodInterceptor实现切面

 MyMethodInterceptor

 AopConfig 

 NeedCut 注解

 GirlController 

 配置文件


一、简介

  1. 它不属于spring;

  2. AspectJ是一个AOP的框架;

  3. 定义了AOP语法;

  4. 有一个专门的编译器用来生成遵守Java字节编码规范的Class文件

二、什么是AspectJ

AspectJ是使用面向切面的一个框架

它扩展了Java语言(它本身也是一种语言)

支持原生Java代码 有自己的编译器

将代码翻译成Java字节码文件

是为了方便编写AOP代码而出现的

使用AOP编程的三个重点 通知 切点 织入

AOP 思想概述

AOP(Aspect Oriented Programming)是一种面向切面的编程思想。面向切面编程是将程序抽象成各个切面,即解剖对象的内部,将那些影响了多个类的公共行为抽取到一个可重用模块里,减少系统的重复代码,降低模块间的耦合度,增强代码的可操作性和可维护性。

AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理、增强处理。

AOP 实现方式

AOP 的初衷是,保证开发者不修改源代码的前提下,为系统中的业务组件添加某种通用功能。AOP 的本质是由 AOP 框架修改业务组件的源代码,达到增强功能的目的。按照 AOP 框架修改源代码的时机,可以将其分为两类:

  • 静态 AOP 实现:AOP 框架在编译阶段对程序源代码进行修改,生成了静态的 AOP 代理类(生成的 *.class 文件已经被改掉了,需要使用特定的编译器),比如 AspectJ。

  • 动态 AOP 实现:AOP 框架在运行阶段动态生成代理对象(在内存中以 JDK 动态代理,或 CGlib 动态地生成 AOP 代理类),如 SpringAOP。

AOP 特性概念

  • 通知(Advice): AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理。

  • 连接点(Join point): 连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出。在 Spring AOP 中,连接点总是方法的调用。

  • 切点(PointCut): 可以插入增强处理的连接点。

  • 切面(Aspect): 切面是通知和切点的结合。

  • 引入(Introduction):允许我们向现有的类添加新的方法或者属性。

  • 织入(Weaving): 将增强处理添加到目标对象中,并创建一个被增强的代理对象。

切点指示器 

 通知类型

三、实现AOP的方式

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
 </dependency>
@Aspect
@Component
public class MyAOP {
    // 定义切入点
    @Pointcut("execution(* com.chensir.controller.*.*(..))")
    public void point() {}

    // 前置通知
    @Before("point()")
    public void before() {
        System.out.println("前置通知");
    }
    // 后置通知 始终会执行
    @After("point()")
    public void after() {
        System.out.println("后置通知");
    }
    // 环绕通知
    @Around("point()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("环绕前");
        Object result = pjp.proceed();
        System.out.println("环绕后");
        return result;
    }
    // 后置 发生异常时不会执行
    @AfterReturning("point()")
    public void returning() {
        System.out.println("After returning 后置");
    }
    // 发生异常
    @AfterThrowing("point()")
    public void throwing() {
        System.out.println("发生异常了");
    }

}

四、配置说明

//定义切入点
//两种占位符
//* 代表的是一个单词,b* 代表的是以b开头的单词。 例如 bds
//.. 通配符 ,代表的是0个或者多个匹配项
//@Pointcut("execution(* com.chensir.service..*.*(..))")  //com.chensir.service 下面以及子包所有类的所有方法
//@Pointcut("execution(* com.chensir.service..*.*(java.lang.String,..))")  //com.chensir.service 下面以及子包所有类的,第一个参数是String类型的方法
//@Pointcut("execution(* com.chensir.service.*.*(..))")  //com.chensir.service 下面所有类的所有方法
//execution(* com.bao.User.add(..))  com.bao.user类下面的add方法
//excution(* com.bao.user.*(..))   com.bao.user下的所用方法

//配置com.bao.User下的add()

execution(* com.bao.User.add(..))

//配置com.bao.User下的所有方法

execution(* com.bao.User.*(..))

//配置所有包下的所有方法

execution(**.*(..))

//配置所有包下的a开头方法

execution(* a*(..))

//配置com.service包下的所有类的所有方法

execution(* com.service.*.*(..)))

自定义注解作为切点

 NeedCut 

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Deprecated
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NeedCut {
}

 MyAop 

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

@Aspect
@Component
public class MyAop {
    // 定义切入点
//    @Pointcut("execution(* com.chensir.controller.*.*(..))")
    @Pointcut("@annotation(com.chensir.annotation.NeedCut)")
    public void point() {}

    // 前置通知
    @Before("point()")
    public void before() {
        System.out.println("---------前置通知--------");
    }
    // 后置通知 始终会执行
    @After("point()")
    public void after() {
        System.out.println("----------后置通知-------");
    }
    // 环绕通知
    @Around("point()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("-------环绕前----------");
        Object result = pjp.proceed();
        System.out.println("---------环绕后-----------");
        return result;
    }

    // 后置 发生异常时不会执行
    @AfterReturning("point()")
    public void returning() {
        System.out.println("------After returning 后置------------");
    }

    // 发生异常
    @AfterThrowing("point()")
    public void throwing() {
        System.out.println("-------发生异常了----------");
    }

}

 GirlController 

@RestController
@RequestMapping("/api")
public class GirlController {

    @GetMapping("/kiss")
    @NeedCut
    public String kiss(){
        return "么么哒";
    }

    @GetMapping("/kiss2")
    public String kiss2(){
        return "么么哒";
    }
}

kiss使用了@NeedCut注解,调用时能够走aop拦截;而kiss2没有加@NeedCut注解,调用时不会走aop拦截

继承MethodInterceptor实现切面

 MyMethodInterceptor

import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import java.lang.reflect.Method;



@Slf4j
public class MyMethodInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        // 获取方法
        Method method = invocation.getMethod();
        //获取参数
        Object[] arguments = invocation.getArguments();
        //获取返回值
        Object proceed = invocation.proceed();
        log.info("方法:{},参数:{},返回值:{}", method.getName(), JSONUtil.toJsonStr(arguments), proceed);
        return proceed;
    }
}

 AopConfig 

import com.chensir.interceptor.MyMethodInterceptor;
import org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

@Configuration
public class AopConfig {

    @Value("${aop.MethodInterceptor.point}")
    private String point;

    @Bean
    public AspectJExpressionPointcutAdvisor aspectJExpressionPointcutAdvisor(){
        AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
        advisor.setAdvice(new MyMethodInterceptor());
        advisor.setExpression(point);
        return advisor;
    }
}

 NeedCut 注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Deprecated
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NeedCut {
}

 GirlController 


@RestController
@RequestMapping("/api")
public class GirlController {

    @GetMapping("/kiss")
    @NeedCut
    public String kiss(Integer id){
        return "么么哒";
    }

    @GetMapping("/kiss2")
    public String kiss2(){
        return "么么哒";
    }
}

 配置文件


#aop.MethodInterceptor.point = execution(* com.chensir.controller.*.*(..))

# 使用注解方式
aop.MethodInterceptor.point = @annotation(com.chensir.annotation.NeedCut)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/844087.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何将安卓 Gradle 模块打包发布到本地 Maven 仓库

文章目录 具体流程 笔者的运行环境&#xff1a; Android Studio Flamingo | 2022.2.1 Android SDK 33 Gradle 8.0.1 JDK 17 Android 的 Gradle 项目与一般的 Gradle 项目是不同的&#xff0c;因此对将 Gradle 模块打包发布到本地 Maven 仓库来说&#xff0c;对普通 Gradle …

Python 模块 locust 性能测试

简介 locust 是 Python 的一个开源的负载测试工具&#xff0c;用于测试网络应用程序的性能和可伸缩性。它使用Python编写&#xff0c;并提供了一个简单易用的语法来定义和执行负载测试。locust模块允许用户模拟大量并发用户并观察系统在高负载下的响应情况。 目录 1. 基本用法…

vue中transition动画的使用

1.vue文件 说明&#xff1a;加name属性 <transition name"sort"><div class"sort" v-show"show"><div class"all-sort-list2" click"goSearch"><div class"item bo" v-for"(item1, in…

图像膨胀+滤波达到边缘外扩模糊效果

有一个扯淡需求, 根据某些格网值渲染对应的颜色, 我们做的实现方案是按照色代码渐变做颜色映射, 但是某些厂家不顾结果正确性与否, 应是为了好看做的好看, 将边界膨胀模糊, 一个非风场,力场类似场数据做了一个类似场的渲染效果, 也不知道说啥好, 例如原始图渲染如下 经过一系列…

初识http协议,简单实现浏览器和服务器通信

文章目录 认识urlhttp协议格式通信代码验证细节Util.hppprotocol.hppServer.hppServer.cc 结果分析 认识url 平时俗称的 “网址” 其实就是说的 URL&#xff0c;例如在百度上搜索一个C 可以看到这段网址前面有个 https 那么这个就代表着使用的是https协议&#xff0c;现在都是…

0807hw

1. 2. (1)a100,b10; a10,b100;//值传递 (2)*a100,*b10; a100,b10;//地址传递 (3)*a100,*b10; a10,b100;

深入探索 Splashtop Enterprise 的潜力

在当今高度技术化的环境中&#xff0c;远程访问解决方案已成为无数组织的支柱。远程访问解决方案缩短了员工与工作之间的地理差距&#xff0c;提高了工作的效率和灵活性&#xff0c;促进形成了无缝的工作体验。在众多远程访问解决方案中&#xff0c;Splashtop Enterprise 作为远…

FFmpeg中AVIOContext的使用

通过FFmpeg对视频进行编解码时&#xff0c;如果输入文件存在本机或通过USB摄像头、笔记本内置摄像头获取数据时&#xff0c;可通过avformat_open_input接口中的第二个参数直接指定即可。但如果待处理的视频数据存在于内存块中时&#xff0c;该如何指定&#xff0c;可通过FFmpeg…

Linux初识网络基础

目录 网络发展 认识“协议 ” 网络协议 OSI七层模型&#xff1a; TCP/IP五层&#xff08;或四层&#xff09;模型 网络传输基本流程 网络传输流程图&#xff1a; 数据包封装和封用 网络中的地址 认识IP地址&#xff1a; 认识MAC地址&#xff1a; 网络发展 1.独立…

JAVA实用工具: 改良版雪花算法-分布式唯一ID神器

Seata内置了一个分布式UUID生成器,用于辅助生成全局事务ID和分支事务ID。具体如下特点: 高性能全局唯一趋势递增这个分布式UUID生成器是基于雪花算法进行改良的,本文针对改良的方法、目的等进行总结 改良点 改良版雪花算法的实现原理参考如下: Seata基于改良版雪花算法的…

redis安装(Windows+Linux)

redis安装 文章目录 redis安装一. windows下安装二.Linux环境下安装 一. windows下安装 下载地址(github): https://github.com/tporadowski/redis/releases (强烈推荐) https://github.com/MicrosoftArchive/redis/releases 选择安装包 下载完成后根据提示进行安装即可(这…

电源控制--品质因素Q值全解

什么是品质因素Q值&#xff1f; 在电源控制中&#xff0c;品质因素 Q 值通常用于描述电源滤波器的性能。电源滤波器用于减小电源中的噪声和干扰&#xff0c;以提供干净稳定的电源供应给电子设备。 品质因素 Q 值在电源滤波器中表示滤波器的带宽和中心频率之比&#xff0c;用于…

VS Code无法跳转,搜索也搜不到

1. 公司安装的加密软件&#xff0c;天锐绿盾&#xff08;绿盾&#xff09;导致VS Code无法使用 如果的绿盾的策略里面没有VS Code的话&#xff0c;就会导致VScode 无法使用&#xff0c;其它软件也是一样&#xff0c;出问题极有可能就是绿盾拦截了&#xff0c;像我的电脑使用wi…

springboot 集成 mybatis-plus 代码生成器

springboot 集成 mybatis-plus 代码生成器 一、导入坐标依赖二、配置快速代码生成器三、自定义代码生成器模板 一、导入坐标依赖 前置依赖&#xff0c;需要用到 mybatis,mysql驱动,lombok插件以及swapper.(因为后面接口测试文档&#xff0c;所以swapper也配了) <dependenc…

Python编程从入门到实践练习第七章:input输入和while循环

目录 一、input输入函数实例 二、while循环2.1 while结构练习题 2.2 使用while循环处理列表和字典2.2.1 在列表之间移动元素2.2.2 删除为特定值的多个列表元素2.2.3 使用用户输入来填充字典练习题 一、input输入函数 input( ) 方法&#xff1a;获取用户的输入信息&#xff0c;使…

【2.2】Java微服务:nacos的使用

✅作者简介&#xff1a;大家好&#xff0c;我是 Meteors., 向往着更加简洁高效的代码写法与编程方式&#xff0c;持续分享Java技术内容。 &#x1f34e;个人主页&#xff1a;Meteors.的博客 &#x1f49e;当前专栏&#xff1a; 深度学习 ✨特色专栏&#xff1a; 知识分享 &…

排序八卦炉之归并、计数

文章目录 1.归并排序1.1初识代码1.2代码分析1.3复杂度1.4非递归版本1.01.初识代码2.代码分析 1.5非递归版本2.01.初识代码2.代码分析 2.计数排序2.1初始代码2.2代码分析 1.归并排序 1.1初识代码 //归并排序 时间复杂度&#xff1a;O(N*logN) 空间复杂度&#xff1a;O(N) vo…

Kaggle First Place Winner Solution Study——多变量回归问题

本期分享一个Kaggle上playground系列多变量回归问题的第一名解决方案。试着分析、复现、学习一下金牌选手的数据分析思路。 赛题链接&#xff1a; Prediction of Wild Blueberry Yield | Kagglehttps://www.kaggle.com/competitions/playground-series-s3e14第一名解决方案链…

前端小练习:案例5.律动爱心

目录 一.效果预览图 二.实现思路 ​编辑 1.html部分 2.css部分 三.完整代码 一.效果预览图 二.实现思路 想要实现爱心律动效果并不难&#xff0c;核心点是关键帧动画。 定义律动爱心需要的元素块&#xff0c;使用定位或者弹性布局等方法&#xff08;定位元素不适合布局&…

【Spring Boot】(一)Spring Boot 项目的创建和使用

文章目录 前言一、什么是 Spring Boot1.1 初识 Spring Boot1.2 Spring Boot 的核心设计思想1.3 Spring Boot 的优点 二、Spring Boot 项目的创建2.1 使用 IDEA 创建2.2 使用网页创建2.3 项目的目录结构 三、Hello World3.1 运行启动类3.2 通过浏览器页面输出 Hello World3.3 约…