【Spring】一文带你彻底搞懂IOC、AOP

目录

首先简单了解一下什么是spring框架

什么是IOC?

什么是依赖注入(DI)?

控制反转和依赖注入又有什么关系?

AOP是什么? 

SpringAOP的实现

说了这么多抽象概念,举个实例方便理解


首先简单了解一下什么是spring框架

        Spring是一个轻量级的框架,通过IOC达到松耦合的目的,使用AOP可以分离应用业务逻辑和系统服务进行内聚性的开发(不改变原有逻辑的同时对业务进行增强),不够配置各种组件的时候相对繁琐,因此后面演进除了SpringBoot框架。

        使用Spring之后可以让我们不用过多关注底层的技术细节,而是更加关注业务上的逻辑的实现

什么是IOC?

        Inverse of Control ——控制反转,是一种思想,这种控制反转的思想主要指的是将对象的创建、组装、管理都从代码中自己实现转移到了外部容器中来帮我们进行实现。在传统的开发方式当中,我们直接手写代码去主动创建和组装对象(将对象所需要的属性注入);在IOC思想中,这个过程被反转了,即由外部容器负责创建和管理对象。

        在IOC中,我们将应用程序设计成一个个的组件,每个组件提供一定的功能,并通过接口与其他组件进行交互。通过IOC容器,我们可以把这些组件注册并配置,容器负责根据配置信息创建组件实例,并维护它们之间的依赖关系和生命周期。

什么是依赖注入(DI)?

        依赖注入指的是将对象所依赖的其他对象(即依赖)注入到当前对象之中,而不是由对象自己去创建或查找他要依赖的对象

        在传统的开发方式当中,对象通过直接创建或查找依赖的对象来获取所需的依赖。

        而在DI中,对象不负责创建或查找的过程,而是通过构造函数、工厂方法或属性的方式接收依赖对象。这样,依赖对象的创建和管理由外部容器负责,对象只需要专注于自身的功能实现。

        依赖注入可以通过构造函数注入、setter方法注入或接口注入等方式来实现。

控制反转和依赖注入又有什么关系?

        在Spring中,IOC是一种设计思想,而DI是IOC的一种具体的实现方式。实际上DI是IOC的实现技术中的一种,它通过依赖注入来实现控制反转。

        IOC思想提倡将对象的设计与创建交给外部容器,并通过xml配置文件、注解、或者Java Config等方式来描述和配置对象之间的依赖关系,

        Spring框架提供了一个IOC容器,即ApplicationContext,它就实现类DI的功能。在Spring中,我们可以使用XML配置文件、注解、或Java Config等方式来描述和配置对象之间的依赖关系,然后Spring容器会根据配置信息来创建对象并完成注入。

AOP是什么? 

        AOP即面向切面编程,可以将那些与业务不想关但是很多业务都需要调用的代码提取出来,思想就是不侵入原有代码的同时对功能进行增强。

        AOP通过定义一个切面,切面可以横切到应用程序的多个模块中,并添加增强的行为。这样我们就可以将通用的功能逻辑从业务逻辑中解耦出来,提高代码的可维护性和重用性。

切面由切点(Pointcut)和通知(Advice组成)

  1. 切点定义的是在程序中的哪个位置进行拦截,通常使用表达式来指定匹配的连接点(join Point)
  2. 通知定义了要在切点执行的代码,可以在切点之前、切点之后或者周围执行特定的逻辑
  3. 常见的通知类包括前置通知(Before Advice)、后置通知(After Advice)、异常通知(After Throwing Advice)和环绕通知(Around Advice)等。

SpringAOP的实现

        SpringAOP是基于动态代理实现的,动态代理有两种,一种是JDK动态代理,另一种是Cglib动态代理

        jdk动态代理是利用反射的原理来实现的,需要调用反射包下的Proxy类的newProxyInstance方法来返回代理对象,这个方法中有三个参数,分别是用于加载代理类的类加载器被代理类实现的接口的class数组用于增强方法的InvocatioHandler实现类

        cglib动态代理原理是利用asm开源包来实现的,是把被代理类的class文件加载进来,通过修改它的字节码生成子类来处理

        jdk动态代理要求代理类必须有实现的接口,生成的动态代理类会和代理类实现同样的接口,cglib则,生成的动态代理类会继承被代理类。Spring默认使用jdk动态代理,当要被代理的类没有实现任何接口的时候采用cglib

说了这么多抽象概念,举个实例方便理解

这是一个实现统计controller路由访问次数的代码

package com.qcby.springbootdemo.aop;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;import java.util.HashMap;
import java.util.Map;@Aspect
@Component
public class MethodCount {// 声明一个Map类型的对象,用于存储方法调用次数private Map<String, Integer> count = new HashMap<>();// 定义切点,表示拦截com.qcby.springbootdemo.Controller包下的所有方法@Pointcut("execution(* com.qcby.springbootdemo.Controller.*.*(..))")public void count() {System.out.println("切点方法执行");   //声明切点,并不会实际调用}// 环绕通知,在目标方法执行前后进行拦截@Around("count()")public Object methodExec(ProceedingJoinPoint pjp) throws Throwable {System.out.println("方法执行前");// 获取方法签名信息Signature signature = pjp.getSignature();String name = signature.getName();System.out.println(name);   //-----loginSystem.out.println(signature.getDeclaringTypeName());  //---com.qcby.springbootdemo.Controller.LoginController// 获取方法参数Object[] args = pjp.getArgs();for (Object arg : args) {System.out.println("aop arg:" + arg);}Object result = null;System.out.println(signature.toLongString());System.out.println();// 统计方法调用次数,使用方法的签名作为keyString key = signature.toLongString();count.put(key, count.getOrDefault(key, 0) + 1);// 执行目标方法result = pjp.proceed();System.out.println("方法执行后");// 输出访问路由次数System.out.println(count);return result;}
}
@Aspect,表示这个类为切面类

 // 定义切点,表示拦截com.qcby.springbootdemo.Controller包下的所有方法
@Pointcut("execution(* com.qcby.springbootdemo.Controller.*.*(..))")
public void count() {
    System.out.println("切点方法执行");   //声明切点,并不会实际调用
}

 

在拦截count()方法这个切点之后,对原方法————Controller中访问路由的方法,在执行期间进行环绕,在methodExec方法中写明具体的环绕逻辑
// 环绕通知,在目标方法执行前后进行拦截
@Around("count()")

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

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

相关文章

Spark整合hive的时候出错

Spark整合hive的时候 连接Hdfs不从我hive所在的机器上找&#xff0c;而是去连接我的集群里的另外两台机器 但是我的集群没有开 所以下面就一直在retry 猜测&#xff1a; 出现这个错误的原因可能与core-site.xml和hdfs-site.xml有关&#xff0c;因为这里面配置了集群的nameno…

高等职业学校物联网实训室建设方案

一、概述 1.1专业背景 物联网&#xff08;Internet of Things&#xff09;被称为继计算机、互联网之后世界信息产业第三次浪潮&#xff0c;它并非一个全新的技术领域&#xff0c;而是现代信息技术发展到一定阶段后出现的一种聚合性应用与技术提升&#xff0c;是随着传感网、通…

无涯教程-分类算法 - Python实现函数

为了在Python中实现SVM&#xff0c;无涯教程将从标准库导入开始&#xff0c;如下所示- import numpy as np import matplotlib.pyplot as plt from scipy import stats import seaborn as sns; sns.set() 接下来&#xff0c;从sklearn.dataset.sample_generator创建具有线性可…

Ceph源码解析:PG peering

集群中的设备异常(异常OSD的添加删除操作)&#xff0c;会导致PG的各个副本间出现数据的不一致现象&#xff0c;这时就需要进行数据的恢复&#xff0c;让所有的副本都达到一致的状态。 一、OSD的故障和处理办法&#xff1a; 1. OSD的故障种类&#xff1a; 故障A&#xff1a;一…

element-ui table表格滚动条拉到最右侧 表头与内容不能对齐

1.问题概述 当表格数据太多&#xff0c;会出现纵向滚动条和横向滚动条&#xff0c;把横向滚动条拉到最右侧时&#xff0c;会出现表头与内容不能对齐的现象。 2.解决方法 1.当页面数据加载完毕后&#xff0c;在后面加上 this.$nextTick(() > {this.$refs.table.doLayout()…

【微服务部署】01-Kubernetes部署流程

文章目录 部署1. Kubernetes是什么2. Kubernetes的优势3. 环境搭建4. 应用部署 部署 1. Kubernetes是什么 Kubernetes是一个用于自动部署、扩展和管理容器化应用程序的开源系统 2. Kubernetes的优势 自动化容器部署资源管理与容器调度服务注册发现与负载均衡内置配置与秘钥…

【缓存设计】记一种不错的缓存设计思路

文章目录 前言场景设计思路小结 前言 之前与同事讨论接口性能问题时听他介绍了一种缓存设计思路&#xff0c;觉得不错&#xff0c;做个记录供以后参考。 场景 假设有个以下格式的接口&#xff1a; GET /api?keys{key1,key2,key3,...}&types{1,2,3,...}其中 keys 是业务…

Gitlab设置中文

1. 打开设置 2.选择首选项Preferences 3. 下滑选择本地化选项Localization&#xff0c;设置简体中文&#xff0c;然后保存更改save changes。刷新网页即可。

Rabbitmq的Federation Exchange

(broker 北京 ) &#xff0c; (broker 深圳 ) 彼此之间相距甚远&#xff0c;网络延迟是一个不得不面对的问题。有一个在北京的业务(Client 北京 ) 需要连接 (broker 北京 ) &#xff0c;向其中的交换器 exchangeA 发送消息&#xff0c;此时的网络延迟很小&#xff0c;(C…

开源文库系统moredoc

什么是 moredoc &#xff1f; moredoc 中文名 魔豆文库&#xff0c;是基于 golang 开发的类似百度文库、新浪爱问文库的开源文库系统&#xff0c;支持 TXT、PDF、EPUB、MOBI、Office 等格式文档的在线预览与管理&#xff0c;为 dochub 文库(github, gitee &#xff09;的重构版…

k8s的交付与部署案例操作

一 k8s的概念 1.1 k8s k8s是一个轻量级的&#xff0c;用于管理容器化应用和服务的平台。通过k8s能够进行应用的自动化部署和扩容缩容。 1.2 k8s核心部分 1.prod: 最小的部署单元&#xff1b;一组容器的集合&#xff1b;共享网络&#xff1b;生命周期是短暂的&#xff1b; …

【c语言】结构体内存对齐,位段,枚举,联合

之前学完结构体&#xff0c;有没有对结构体的大小会很疑惑呢&#xff1f;&#xff1f;其实结构体在内存中存储时会存在内存对齐&#xff0c;捎带讲讲位段&#xff0c;枚举&#xff0c;和联合&#xff0c;跟着小张一起学习吧 结构体内存对齐 结构体的对齐规则: 第一个成员在与结…

kafka复习:(22)一个分区只能被消费者组中的一个消费者消费吗?

默认情况下&#xff0c;一个分区只能被消费者组中的一个消费者消费。但可以自定义PartitionAssignor来打破这个限制。 一、自定义PartitionAssignor. package com.cisdi.dsp.modules.metaAnalysis.rest.kafka2023;import org.apache.kafka.clients.consumer.internals.Abstrac…

索引,事务,存储引擎

索引是一个排序的列表&#xff0c;在这个列表中存储着索引的值和包含这个值的数据所在行的物理地址&#xff08;类似于C语言的链表通过指针指向数据记录的内存地址&#xff09;。 使用索引后可以不用扫描全表来定位某行的数据&#xff0c;而是先通过索引表找到该行数据对应的物…

【BUG事务内消息发送】事务内消息发送,事务还未结束,消息发送已被消费,查无数据怎么解决?

问题描述 在一个事务内完成插入操作&#xff0c;通过MQ异步通知其他微服务进行事件处理。 由于是在事务内发送&#xff0c;其他服务消费消息&#xff0c;查询数据时还不存在如何解决呢&#xff1f; 解决方案 通过spring-tx包的TransactionSynchronizationManager事务管理器解…

LeetCode 热题 100(七):105. 从前序与中序遍历序列构造二叉树、14. 二叉树展开为链表

题目一&#xff1a; 105. 从前序与中序遍历序列构造二叉树https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ 思路&#xff1a;依据前序遍历的根左右和中序遍历的左根右&#xff0c; 且根左长度&#xff1d;左根 代码&#xff1a; …

Qt:qRegisterMetaType为Qt信号和槽添加自定义参数类型

背景 qt信号和槽之间的参数传递默认只能传递qt内部已有的类型&#xff0c;例如QString等&#xff0c;若我们自定义类型作为参数时&#xff0c;虽然编译不会报错&#xff0c;但运行时会提示connect无效&#xff0c;无法识别自定义的类。 此时需要我们将自定义类进行注册&#…

C#搭建WebSocket服务实现通讯

在学习使用websocket之前我们先了解一下websocket&#xff1a; WebSocket是一种在单个TCP连接上进行全双工通信的通信协议。与HTTP协议不同&#xff0c;它允许服务器主动向客户端发送数据&#xff0c;而不需要客户端明确地请求。这使得WebSocket非常适合需要实时或持续通信的应…

纯 CSS 开关切换按钮

<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>纯 CSS 开关切换按钮</title><style>html {font-size: 62.5%;}body {background-color: #1848a0;}.wrapper {position: absolute;left: …

swoole协程框架?

Swoole是一个高性能的PHP扩展&#xff0c;可以用于构建异步、并发和高性能的网络应用。它提供了许多底层网络通信和多进程管理的功能&#xff0c;使得开发者可以更轻松地编写高性能的服务器程序。 以下是Swoole的一些主要特点和功能&#xff1a; 异步非阻塞&#xff1a;Swoole…