当前位置: 首页 > news >正文

【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.lryc.cn/news/144299.html

相关文章:

  • 国际旅游网络的大数据分析(数学建模练习题)
  • 音视频技术开发周刊 | 308
  • 多旋翼飞控底层算法开发系列实验 | 多旋翼动力系统设计实验3
  • Redis之Sentinel(哨兵)机制
  • 加密的PDF文件,如何解密?
  • 【java】获取当前年份
  • 前端面试话术集锦第一篇
  • NeRFMeshing - 精确提取NeRF中的3D网格
  • 后端面试话术集锦第五篇:rabbitmq面试话术
  • Spring Boot(Vue3+ElementPlus+Axios+MyBatisPlus+Spring Boot 前后端分离)【一】
  • vue3之reactive和ref学习篇
  • 【推荐】Spring与Mybatis集成整合
  • listdir, makedirs, shuffle, exists, webdriver.Chrome, roll方法快速查阅
  • java.nio.ByteBuffer 学习笔记
  • 自动化实时在线静电监控系统的构成
  • Windows 转 mac 记录
  • Linux_4_文本处理工具和正则表达式
  • [Unity]VSCode无代码提示
  • 画流程图都可以用哪些工具?
  • Elasticsearch中倒排索引、分词器、DSL语法使用介绍
  • rabbitmq笔记-rabbitmq进阶-数据可靠性,rabbitmq高级特性
  • 【笔记】判断两个String字符串是否相同(考虑字符串为null的情况)
  • 【校招VIP】java语言考点之多线程NIO
  • JVM知识点(一)
  • 网页接口导入postman进行接口请求
  • 【Leetcode】124.二叉树中的最大路径和(Hard)
  • django自动创建model数据
  • vscode 远程连接
  • Error running ‘Tomcat 8.5.29‘ Address localhost:1099 is already in use
  • 后端面试话术集锦第 七 篇:nginx面试话术