Spring_AOP

一、AOP简介

AOP,Aspect Oriented Programming,面向切面编程,是对面向对象编程0OP的升华。OOP是纵向对一个事物的抽象,一个对象包括静态的属性信息,包括动态的方法信息等。而AOP是横向的对不同事物的抽象,属性与属性、方法与方法、对象与对象都可以组成一个切面, 而用这种思维去设计编程的方式叫做面向切面编程。
在这里插入图片描述

二、AOP思想的实现方案

动态代理技术,在运行期间,对目标对象的方法进行增强,代理对象同名方法内可以执行原有逻辑的同时嵌入执行其他增强逻辑或其他对象的方法。
例如:
A对象为我们要增强的目标对象,B对象为增强方法所在的对象。在动态代理后,我们会获得一个A对象的
在这里插入图片描述
接下来我们通过这种方式来增强spring容器中的一个Bean
(项目创建成功之后的目录)不要忘了,每个bean都需要被spring容器管理,所以需要在类上添加注解@Component或者@Service
在这里插入图片描述
① 首先创建一个项目,创建Userservice接口,并实现它,这个UserServiceImpl对象就相当于A对象

public interface UserService {
    public void show1();

    public void show2();
}
@Service
public class UserServiceImpl implements UserService {
    @Override
    public void show1() {
        System.out.println("UserServiceImpl show1");
    }

    @Override
    public void show2() {
        System.out.println("UserServiceImpl show2");
    }
}

②然后创建增强类Advice,相当于B对象

@Component
public class MyAdvice {
    public void beforeAdvice(){
        System.out.println("前置增强...");
    }
    public void afterAdvice(){
        System.out.println("后置增强...");
    }
}

③最后创建一个Bean的后置处理类,这个后置处理类会返回一个被增强的bean,相当于A对象的Proxy对象

@Component
public class MockAopBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        //目的:对UserServiceImpl中的show1和show2方法进行增强,增强方法存在于MyAdvice中
        //问题1:筛选service.impl包下的所有方法都可以进行增强,解决方法是if-else
        //问题2:如果获取MyAdvice,解决方案从Spring容器中获取

        //加一个条件判断,只有在"com.itheima.service.impl"包下的bean才能够被增强
        if(bean.getClass().getPackage().getName().equals("com.itheima.service.impl")){
            //使用Proxy类生成当前获取到的对象的代理对象
            Object beanProxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    //获取增强方法所在的对象
                    MyAdvice advice = applicationContext.getBean(MyAdvice.class);
                    //执行前置增强方法
                    advice.beforeAdvice();
                    //执行目标方法
                    Object result = method.invoke(bean,args);//执行bean的目标方法,携带参数
                    //执行后置增强方法
                    advice.afterAdvice();
                    return result;
                }
            });
            return beanProxy;
        }
        return bean;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

三、Spring_AOP的相关概念

在这里插入图片描述

四、基于xml配置的AOP

1.xml方式AOP快速入门

2.步骤

1.导入AOP相关坐标
2.准备目标类、准备增强类、并配置给Spring管理
3.配置切点表达式(哪些方法被增强)
4.配置织入(切点被哪些方法增强,是前置增强还是后置增强)

五、基于注解的方式配置的AOP

1.AOP的注解介绍

注解作用
@Aspect切面声明,标注在类、接口(包括注解类型)或枚举上。
@Pointcut切入点声明,即切入到哪些目标类的目标方法。既可以用 execution 切点表达式, 也可以是annotation 指定拦截拥有指定注解的方法。value 属性指定切入点表达式,默认为 “”,用于被通知注解引用,这样通知注解只需要关联此切入点声明即可,无需再重复写切入点表达式
@Before前置通知, 在目标方法(切入点)执行之前执行。value 属性绑定通知的切入点表达式,可以关联切入点声明,也可以直接设置切入点表达式。注意:如果在此回调方法中抛出异常,则目标方法不会再执行,会继续执行后置通知 -> 异常通知。
@After后置通知, 在目标方法(切入点)执行之后执行
@AfterReturning返回通知, 在目标方法(切入点)返回结果之后执行。pointcut 属性绑定通知的切入点表达式,优先级高于 value,默认为 “”
@AfterThrowing异常通知, 在方法抛出异常之后执行, 意味着跳过返回通知pointcut 属性绑定通知的切入点表达式,优先级高于 value,默认为 " " 注意:如果目标方法自己 try-catch 了异常,而没有继续往外抛,则不会进入此回调函数
@Around环绕通知:目标方法执行前后分别执行一些代码,类似拦截器,可以控制目标方法是否继续执行。通常用于统计方法耗时,参数校验等等操作。

正常流程:【环绕通知-前】-> 【前置通知】-> 【返回通知】-> 【后置通知】->【环绕通知-后】。

2.AOP的切点表达式

切点表达式是配置要对哪些连接点(哪些类的哪些方法)进行通知的增强,语法如下:
execution ( [访问修饰符] 返回值类型 包名.类名.方法名(参数) )
其中:
1.访问修饰符可以省略不写
2.返回值类型、某一级的包名、类名、方法名可以使用*表示任意
3.包名与类型之间使用单点.表示该包下的类,使用双点 .. 表示该包及其子包下的所有类
4.参数列表可以使用两个点..表示任意参数
例如 "execution(* com.itheima.service.impl.*.*(..))"
表示权限修饰符默认、任意返回值类型、com.itheima.service.impl包下、所有类、所有方法、任意个参数

在这里插入图片描述

3.注解方式AOP快速入门

4.步骤

1.导入AOP相关坐标

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2.准备目标类并配置给Spring管理

@Service
public class UserServiceImpl implements UserService {
    @Override
    public void show1() {
//        int a = 1/0;
        System.out.println("UserServiceImpl show1");
    }

    @Override
    public void show2() {
        System.out.println("UserServiceImpl show2");
    }
}

3.使用注解配置切点、切面类、通知类型等

@Component
@Aspect
public class MyAdvice2 {
    @Before("execution(* com.itheima.service.impl.*.*(..))")
    public void beforeAdvice(JoinPoint joinPoint){
        System.out.println("当前增强的对象是:"+joinPoint.getTarget());
        System.out.println("表达式:"+joinPoint.getStaticPart());
        System.out.println("注解配置的前置增强...");
        System.out.println("======================");
    }

    @AfterReturning("execution(* com.itheima.service.impl.*.*(..))")
    public void afterReturningAdvice(JoinPoint joinPoint){
        System.out.println("当前增强的对象是:"+joinPoint.getTarget());
        System.out.println("表达式:"+joinPoint.getStaticPart());
        System.out.println("注解配置的后置增强...");
        System.out.println("======================");
    }

    @Around("execution(* com.itheima.service.impl.*.*(..))")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("当前增强的对象是:"+proceedingJoinPoint.getTarget());
        System.out.println("表达式:"+proceedingJoinPoint.getStaticPart());
        System.out.println("环绕的前置增强");
        Object proceed = proceedingJoinPoint.proceed();//执行目标方法
        System.out.println("环绕的后置增强");
        System.out.println("======================");
        return proceed;
    }

    @AfterThrowing(pointcut = "execution(* com.itheima.service.impl.*.*(..))",throwing = "e")
    public void afterThrowingAdvice(Throwable e){
        System.out.println("当前的异常信息为:"+e);
        System.out.println("异常抛出通知...报异常才执行");
        System.out.println("======================");
    }

    @After("execution(* com.itheima.service.impl.*.*(..))")
    public void afterAdvice(){
        System.out.println("最终的增强");
        System.out.println("======================");
    }
}

4.启动类注解@EnableAspectJAutoProxy开启Spring AOP

@SpringBootApplication
@EnableAspectJAutoProxy
public class SpringAopTest01Application {

    public static void main(String[] args) {
        SpringApplication.run(SpringAopTest01Application.class, args);
    }

}

在第三步,使用注解配置通知类型和切点时,五种通知类型中都使用了"execution(* com.itheima.service.impl.*.*(..))"。这样显然是不够优雅的。
我们可以将切点抽取出来:

@Component
@Aspect
public class MyAdvice2 {
    //抽取切点出来
    @Pointcut("execution(* com.itheima.service.impl.*.*(..))")
    public void myPointCut(){}

//    @Before("execution(* com.itheima.service.impl.*.*(..))")
    @Before("myPointCut()")
    public void beforeAdvice(JoinPoint joinPoint){
        System.out.println("当前增强的对象是:"+joinPoint.getTarget());
        System.out.println("表达式:"+joinPoint.getStaticPart());
        System.out.println("注解配置的前置增强...");
        System.out.println("======================");
    }

//    @AfterReturning("execution(* com.itheima.service.impl.*.*(..))")
    @AfterReturning("myPointCut()")
    public void afterReturningAdvice(JoinPoint joinPoint){
        System.out.println("当前增强的对象是:"+joinPoint.getTarget());
        System.out.println("表达式:"+joinPoint.getStaticPart());
        System.out.println("注解配置的后置增强...");
        System.out.println("======================");
    }

//    @Around("execution(* com.itheima.service.impl.*.*(..))")
    @Around("myPointCut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("当前增强的对象是:"+proceedingJoinPoint.getTarget());
        System.out.println("表达式:"+proceedingJoinPoint.getStaticPart());
        System.out.println("环绕的前置增强");
        Object proceed = proceedingJoinPoint.proceed();//执行目标方法
        System.out.println("环绕的后置增强");
        System.out.println("======================");
        return proceed;
    }

//    @AfterThrowing(pointcut = "execution(* com.itheima.service.impl.*.*(..))",throwing = "e")
    @AfterThrowing(value = "myPointCut()",throwing = "e")
    public void afterThrowingAdvice(Throwable e){
        System.out.println("当前的异常信息为:"+e);
        System.out.println("异常抛出通知...报异常才执行");
        System.out.println("======================");
    }

//    @After("execution(* com.itheima.service.impl.*.*(..))")
    @After("myPointCut()")
    public void afterAdvice(){
        System.out.println("最终的增强");
        System.out.println("======================");
    }
}

这样基于注解方式的AOP就编写完成了,我们测试一下,调用com.itheima.service.impl包下的类的方法
在这里插入图片描述
在这里插入图片描述
运行结果:在这里插入图片描述
可以看到这些增强方法都执行了,而且我们并没有修改目标方法。一点原代码都没动,直接在切面类上配置需要被增强的方法的签名,就实现了方法增强,这就是AOP。

六、使用AOP实现日志功能

上面我们使用AOP实现了对方法的增强,这里我们继续使用AOP实现项目中常用的日志记录功能。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

cs231n assignment2 q5 PyTorch on CIFAR-10

文章目录 嫌啰嗦直接看源码Q5 :PyTorch on CIFAR-10three_layer_convnet题面解析代码输出 Training a ConvNet题面解析代码输出 ThreeLayerConvNet题面解析代码输出 Train a Three-Layer ConvNet题面解析代码输出 Sequential API: Three-Layer ConvNet题面解析代码输出 CIFAR-1…

【MongoDB】解决ProxmoxVE下CentOS7虚拟机安装MongoDB6后启动失败的问题

目录 安装步骤&#xff1a; 2.1 配置yum源 2.2 安装MongoDB 2.3 启 动MongoDB ProxmoxVE上新装的CentOS7.4虚拟机&#xff0c;安装MongoDB6。 安装步骤&#xff1a; 2.1 配置yum源 # 创建mongodb yum源&#xff08;https://www.mongodb.com/docs/manual/tutorial/insta…

27岁了学plc还来得及吗?

如果你是学电气或者自控&#xff0c;完全没问题&#xff0c;PLC其实只是你的理解力的问题&#xff0c;真正底层的&#xff0c;都帮你打包了&#xff0c;你直接用就是。问题只是&#xff1a;你要能透彻理解 如果你从一个完全陌生的行业转过来&#xff0c;完全没必要。如果本身就…

[数据分析与可视化] Python绘制数据地图5-MovingPandas绘图实例

MovingPandas是一个基于Python和GeoPandas的开源地理时空数据处理库&#xff0c;用于处理移动物体的轨迹数据。关于MovingPandas的使用见文章&#xff1a;MovingPandas入门指北&#xff0c;本文主要介绍三个MovingPandas的绘图实例。 MovingPandas官方仓库地址为&#xff1a;mo…

自定义批量修改图像位深度

什么是图像位深度&#xff1f;&#xff1f;&#xff1f; 图像位深度(Bit Depth)是指图像中每个像素所占的比特数,它决定了图像能够表示的颜色数量和亮度层级。 简单来说: 位深度越高,每个像素所能表示的颜色数和亮度等级越多。位深度越低,每个像素所能表示的颜色数和亮度等级…

容器安全的常见风险与防护实践

运行在云平台上的容器产品&#xff0c;因为具备一个完整的可移植应用程序环境&#xff0c;能够帮助用户轻松地完成对应用程序的开关控制&#xff0c;提升应用程序的敏捷性&#xff0c;同时节约企业的IT建设成本。在巨大优势作用下&#xff0c;容器产品的采用率在2021年达到了新…

恒运资本:算力股爆发,地产股全线下挫,海外机构调研股出炉

60股近期获海外组织调研&#xff0c;医疗龙头最受组织重视。 今日早盘三大指数全线低开&#xff0c;延续调整走势&#xff0c;上证指数跌1.01%&#xff0c;深证成指跌1.35%&#xff0c;创业板指跌1.6%。AI概念股逆市走强&#xff0c;算力、数据要素等方向领涨&#xff0c;朗威股…

通达信接口调用过程需要借助什么?

通达信接口是一种用于获取、传输和处理股票市场相关数据的软件接口&#xff0c;以提供了一种连接股票市场数据源和数据使用者之间的通道&#xff0c;允许开发者通过编程方式获取股票行情数据、交易数据和相关信息等。如果调用通达信接口&#xff0c;需要借助以下几个方面的工具…

竞赛项目 深度学习的动物识别

文章目录 0 前言1 背景2 算法原理2.1 动物识别方法概况2.2 常用的网络模型2.2.1 B-CNN2.2.2 SSD 3 SSD动物目标检测流程4 实现效果5 部分相关代码5.1 数据预处理5.2 构建卷积神经网络5.3 tensorflow计算图可视化5.4 网络模型训练5.5 对猫狗图像进行2分类 6 最后 0 前言 &#…

【Linux】网络层、数据链路层、DNS、ICMP协议、NAT技术

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《学会Linux》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录 &#x1f449;网络层&a…

SQL | 检索数据

1-检索数据 1.1-检索单个列 SELECT prod_name FROM Products; 上述SELECT语句从Products表中检索一个名为prod_name的列。 所要查找的列在select后面&#xff0c;from关键字指出从那个表查询数据。 输出如下&#xff1a; prod_name8 inch teddy bear12 inch teddy bear18…

【Unity3D】Shader Graph节点

1 前言 Shader Graph 16.0.3 中有 208 个 Node&#xff08;节点&#xff09;&#xff0c;本文梳理了 Shader Graph 中大部分 Node 的释义&#xff0c;官方介绍详见→Node-Library。 Shader Graph 通过图像的形式表达了顶点变换和片元着色流程&#xff0c;其背后都是一些列的数学…

ubuntu 安装 python

ubuntu 安装 python 初环境与设备查询是否安装安装python 本篇文章将介绍ubuntu 安装 python 初 希望能写一些简单的教程和案例分享给需要的人 环境与设备 系统&#xff1a;ubuntu 查询是否安装 因为系统也许会自带一个python&#xff0c;所以验证一下&#xff0c;如果自…

FPGA应用学习笔记----CORDIC 算法和小结

加减移位操作来运算三角函数&#xff0c;开根号&#xff0c;求对数 圆周旋转模式

【Uni-App】uview 开发多端应用,密码显示隐藏功能不生效问题

出现的问题&#xff1a; 使用uview组件u-input框密码绑定时会出现右侧密码显隐图标不显示的问题 思路&#xff1a; 1.看了下uview源码&#xff0c;发现这有一段注释&#xff0c;我们需要把源码修改一下&#xff0c;问题出在这里 这行代码修改为 :password"password || …

ChatGPT: 提升程序员开发效率的秘密武器!

引言 在现代软件开发中&#xff0c;时间和效率显得尤为重要。程序员们需要在尽可能短的时间内编写高质量的代码&#xff0c;并使之处于状态良好的维护周期。为满足这些需求&#xff0c;人工智能技术逐渐成为软件开发的一项核心能力。ChatGPT作为自然语言生成模型中的佼佼者&am…

K8S MetalLB LoadBalancer

1. 简介 kubernetes集群没有L4负载均衡&#xff0c;对外暴漏服务时&#xff0c;只能使用nodePort的方式&#xff0c;比较麻烦&#xff0c;必须要记住不同的端口号。 LoadBalancer&#xff1a;使用云提供商的负载均衡器向外部暴露服务&#xff0c;外部负载均衡器可以将流量路由…

面部表情识别(Pytorch):人脸检测模型+面部表情识别分类模型

目录 0 相关资料1 基于人脸检测面部表情分类识别方法2 项目安装2.1 平台与镜像2.2 项目下载2.3 模型下载2.4 上传待测试图片2.5 项目安装 3 demo测试 0 相关资料 面部表情识别2&#xff1a;Pytorch实现表情识别(含表情识别数据集和训练代码)&#xff1a;https://blog.csdn.net…

Java:正则表达式书写规则及相关案例:检验QQ号码,校验手机号码,邮箱格式,当前时间

正则表达式 目标:体验一下使用正则表达式来校验数据格式的合法性。需求:校验QQ号码是否正确&#xff0c;要求全部是数字&#xff0c;长度是(6-20&#xff09;之间&#xff0c;不能以0开头 首先用自己编写的程序判断QQ号码是否正确 public static void main(String[] args) {Sy…

camera hal|如何学习一个新平台

全网最具价值的Android Camera开发学习系列资料~ 作者:8年Android Camera开发,从Camera app一直做到Hal和驱动~ 欢迎订阅,相信能扩展你的知识面,提升个人能力~ 我自己目前从事的是android camera hal 的工作,工作上接触到的芯片平台要么是高通的,要么是mtk的。 其实…
最新文章