Spring IOC 和 AOP

embedded/2024/10/21 3:44:04/

相关注解可参考:http://t.csdnimg.cn/yfUKt

1.什么是IOC和AOP

        Spring框架中的IOC(Inverse of Control,控制反转)和AOP(Aspect-Oriented Programming,面向切面编程)是其两大核心特性,它们共同为Java应用程序带来了更高的灵活性、可维护性和松耦合度。

IoC(控制反转)

概念: IoC是一种设计模式,它提倡不直接在代码中创建对象,而是将对象的创建和依赖关系的管理交由一个外部容器(在Spring中,这个容器就是IoC容器)来处理。这样做的好处是降低了组件之间的耦合度,使得组件更易于测试和重用。

工作原理

  • Bean定义:通过XML配置文件、注解或Java配置类定义Bean及其依赖关系。
  • Bean初始化:Spring容器读取这些配置,负责创建Bean实例,并管理Bean的整个生命周期,包括实例化、属性注入、初始化、销毁等。
  • 依赖注入(DI):Spring容器根据配置自动将依赖的Bean注入到需要它们的Bean中,无需Bean自己管理依赖。

AOP(面向切面编程)

概念: AOP是一种编程范式,用于解决那些遍布于各个模块中的交叉关注点(如日志记录、事务管理、安全检查等)的编程问题。它通过定义所谓的“切面”来封装这些横切关注点,然后将其插入到应用程序的其他部分中,而无需修改这些部分的代码。

工作原理

  • 切面(Aspect):封装了横切关注点的模块,如事务管理逻辑就是一个切面。
  • 切点(Pointcut):定义了切面应该在何处应用的规则,可以通过表达式指定匹配的类或方法。
  • 通知(Advice):切面中的实际操作,比如在方法执行前做什么(前置通知)、执行后做什么(后置通知)等。
  • 代理(Proxy):Spring AOP通常通过动态代理(JDK动态代理或CGLIB)来创建目标对象的代理,以实现在不修改原有代码的情况下插入切面逻辑。

IoC与AOP的关系

IoC是Spring的基础,它负责创建Bean并管理Bean之间的依赖关系,而AOP则是建立在IoC之上的高级编程模型,利用IoC容器管理的Bean作为切面操作的目标。两者相辅相成,共同构成了Spring框架强大功能的核心部分,使得开发者能够更加专注于业务逻辑的实现,而非琐碎的基础设施代码。

1.1 IOC(控制反转)

1.1.1 基于XML的形式

1.1.2 基于注解的形式

1.1.2.1 配置类

  • 通过类型去获取:

  • 通过id(名字)去获取:

  • 通过包名也可以进行加载:

1.1.2.2 扫包+注解

1.2 DI(依赖注入)

自动创建对象,完成依赖注入

@Autowried 是通过类型进行注入(byType),如果需要按名字取值(byNamew),就使用@Autowried +@Qualifier的形式,完成名称的映射

注:@Qualifier("config")与@Component("config")名字保持一致

@Resource有两个属性是比较重要的,分别是name和type,默认按byName进行注入,如果无法通过名称匹配到对应的 Bean 的话,注入方式会变为byType;Spring将@Resource注解的name属性解析为bean的名称,type属性解析为bean的类型,如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略,如果同时指定name 和type属性(不建议这么做)则注入方式为byType+byName。

@Resource和@Autowired的区别-CSDN博客

1.3 AOP(面相切面编程)


        面向切面编程,是一种抽象化的面相对象编程,对面向对象编程的一种补充。底层使用动态代理机制来实现。

打印日志:

    • 为了将核心业务与非业务代码进行解耦,所以需要先拆开。
    • 但又不能影响到之前的功能,所以拆开后还需要合并。
    • 合并成一个代理,对代理进行编程。

1.3.1 基于XML配置

(1)新建Maven项目,添加引用,项目的pom.xml文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>springAop</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.15</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.3.15</version></dependency></dependencies>
</project>

(2)创建要被代理的Math类

java">package com.zsh.aop;/*** 被代理的目标类* @Author ZhaoShuHao* @Date 2024/4/29 14:46*/
public class Math {//加public int add(int n1,int n2){int result=n1+n2;System.out.println(n1+"+"+n2+"="+result);return result;}//减public int sub(int n1,int n2){int result=n1-n2;System.out.println(n1+"-"+n2+"="+result);return result;}//乘public int mut(int n1,int n2){int result=n1*n2;System.out.println(n1+"X"+n2+"="+result);return result;}//除public int div(int n1,int n2){int result=n1/n2;System.out.println(n1+"/"+n2+"="+result);return result;}
}

(3)编辑AOP中需要使用到的通知类Advices。

java">package com.zsh.aop;import org.aspectj.lang.JoinPoint;import java.util.Arrays;/*** 通知类,横切逻辑* @Author ZhaoShuHao* @Date 2024/4/29 14:47*/
public class Advices {public void before(JoinPoint jp){System.out.println("----------前置通知----------"+jp.getSignature().getName()+"方法执行了,参数为"+ Arrays.toString(jp.getArgs()));}public void after(JoinPoint jp,Object result){System.out.println("----------最终通知----------"+jp.getSignature().getName()+"方法执行了,结果为:"+result);}
}

(4)配置容器初始化时需要的xml文件。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.3.xsd"><!-- 被代理对象 --><bean id="math" class="com.zsh.aop.Math"></bean><!-- 通知 --><bean id="advices" class="com.zsh.aop.Advices"></bean><!-- aop配置 --><aop:config proxy-target-class="true"><!--切面 --><aop:aspect ref="advices"><!-- 切点 --><aop:pointcut expression="execution(* com.zsh.aop.Math.*(..))" id="point1"/><!--连接通知方法与切点 --><aop:before method="before" pointcut-ref="point1"/><!--            <aop:after method="after" pointcut-ref="point1"/>--><aop:after-returning method="after" pointcut-ref="point1" returning="result"/></aop:aspect></aop:config></beans>

(5)测试Test代码如下。

java">package com.zsh.aop;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** @Author ZhaoShuHao* @Date 2024/4/29 14:49*/
public class Test {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");Math math = ctx.getBean("math", Math.class);int n1 = 66, n2 = 33;math.add(n1, n2);math.sub(n1, n2);math.mut(n1, n2);math.div(n1, n2);}
}

1.3.2 基于注解配置

注:在基于XML配置的基础上进行修改

(1)修改被代理的Math类,在Math类的基础上使用注解,注入到spring

java">package com.zsh.aop;import org.springframework.stereotype.Component;/*** 被代理的目标类* @Author ZhaoShuHao* @Date 2024/4/29 14:46*/
@Component("math")
public class Math {//加public int add(int n1,int n2){int result=n1+n2;System.out.println(n1+"+"+n2+"="+result);return result;}//减public int sub(int n1,int n2){int result=n1-n2;System.out.println(n1+"-"+n2+"="+result);return result;}//乘public int mut(int n1,int n2){int result=n1*n2;System.out.println(n1+"X"+n2+"="+result);return result;}//除public int div(int n1,int n2){int result=n1/n2;System.out.println(n1+"/"+n2+"="+result);return result;}
}

(2)修改AOP中需要使用到的通知类Advices,这里修改后,基本与之前xml中的配置一致

java">package com.zsh.aop;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;import java.util.Arrays;/*** 通知类,横切逻辑* @Author ZhaoShuHao* @Date 2024/4/29 14:47*/
@Component
@Aspect
public class Advices {@Before("execution(public int com.zsh.aop.Math.*(..))")public void before(JoinPoint jp){System.out.println("----------前置通知----------"+jp.getSignature().getName()+"方法执行了,参数为"+ Arrays.toString(jp.getArgs()));}@AfterReturning(value = "execution(public int com.zsh.aop.Math.*(..))",returning = "result")public void after(JoinPoint jp,Object result){System.out.println("----------最终通知----------"+jp.getSignature().getName()+"方法执行了,结果为:"+result);}
}
  • @Component表示该类的实例会被Spring IOC容器管理;
  • @Aspect表示声明一个切面;
  • @Before表示before为前置通知,通过参数execution声明一个切点
  • @AfterReturning后置通知:
    • value = "execution(public int com.zsh.aop.Math.*(..))":这一部分定义了切点表达式,指定了AOP要应用的范围。具体来说:
      • execution是关键字,用于匹配方法执行的连接点。
      • public int指定了匹配的方法必须是具有public访问权限并且返回类型为int的方法。
      • com.zsh.aop.Math.*指定了匹配的类位于com.zsh.aop.Math包下,*表示Math类中的所有方法。
      • (..)表示不关心方法的参数列表,即匹配任意参数。
    • returning = "result":此属性指定了一个形参名称(在此例中为"result"),该形参将在通知方法中用来接收被织入切面的方法的返回值。也就是说,在执行完匹配的方法后,如果该方法有返回值,这个返回值会被传递给通知方法中对应名称的参数。

(4)配置容器初始化时需要的xml文件。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><!--开启自动扫描包--><context:component-scan base-package="com.zsh.aop"></context:component-scan><!--开启aop自动代理--><aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy></beans>
  • 组件扫描 (`context:component-scan):
    • 功能: <context:component-scan> 标签用于指示Spring在指定的包(及其子包)中搜索带有@Component、@Service、@Repository、@Controller等注解的类,并自动注册这些类为Spring管理的Bean。在这个例子中,它会扫描com.example.spring_aop.aop包及其所有子包。
  • AOP自动代理 (`aop:aspectj-autoproxy):
    • 功能: <aop:aspectj-autoproxy> 配置用于开启Spring对AspectJ切面的支持,它会自动为符合条件的Bean创建代理对象,从而实现切面逻辑(如日志记录、权限校验等)的织入。这使得开发者无需手动配置代理就能使用AOP。

(5)测试Test代码如下。

java">package com.zsh.aop;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** @Author ZhaoShuHao* @Date 2024/4/29 14:49*/
public class Test {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");//根据类型//        Math math = ctx.getBean(Math.class);//根据名称Math math = ctx.getBean("math",Math.class);int n1 = 66, n2 = 33;math.add(n1, n2);math.sub(n1, n2);math.mut(n1, n2);math.div(n1, n2);}
}


http://www.ppmy.cn/embedded/37227.html

相关文章

(CDA数据分析师笔记)第六章 业务分析方法五

产品库存类指标 库存手进货与销售双方向的影响。 期初库存&#xff1a;单位时间的起点处库存量。 期末库存&#xff1a;单位时间的终点处库存量。 常见指标&#xff1a; 库存数量与库存金额&#xff1a;可以是某时点或者某时段平均值。 有两个计算方法&#xff1a; 计算方…

leetcode 547.省份数量

思路&#xff1a;dfs 或者这道题用bfs也是可以的。 这道题有点迷惑性&#xff0c;这里的数组给的是无向图的数组&#xff0c;而并不是地图&#xff0c;这里需要着重注意一下。 而后&#xff0c;这里的状态数组st没必要是二维的&#xff0c;我们并不会去遍历所给的数组&#…

如何根据索引删除数组中的元素,并保证删除的正确性

使用 splice() 方法来删除这些索引处的数据 var array [1, 2, 3, 4, 5]; var indexesToDelete [1, 3]; // 需要删除的索引// 将需要删除的索引按照从大到小的顺序排序&#xff0c;以避免删除元素后索引发生变化 indexesToDelete.sort((a, b) > b - a);// 遍历需要删除的索…

计算机行业AI前沿报告:混合专家模型技术(MoE)

今天分享的是****AI系列深度研究报告&#xff1a;《计算机行业AI前沿报告&#xff1a;混合专家模型技术(MoE)》。&#xff08;报告出品方&#xff1a;中信建投证券&#xff09; 精选内容来源公众&#xff1a;见鹿报告 报告共计: 24页 [报告内容摘要如下] **•核心观点&…

JavaScript百炼成仙自学笔记——2

一、循环遍历&#xff1a; 方式一 for(var i0;i<10;i){console.log(i); }方式二 var i 0; while(i < 100){console.log(i);i; }细看代码就是 先定义变量i&#xff0c;再执行{}中的代码&#xff0c;最后改循环变量的值 二、遍历 什么事遍历&#xff1f; 什么时候会用…

UE5 UMG

锚点 切换面板 先将制作好的面板放在屏幕外面&#xff0c;然后点击播放动画按钮利用位移动画将panel移动到屏幕中间 背包 创建物品的结构体&#xff0c;储存物品的信息 创建自定义事件&#xff0c;初始化背包格子的图片显示&#xff0c;然后文本直接绑定就可以&#xff0c;可…

资料总结分享:SAM,bam,bed文件格式

目录 sam文件 bam文件 bed 文件 sam文件 SAM&#xff08;Sequence Alignment/Map&#xff09;文件是存储测序数据比对结果的一种常见格式。SAM文件通常用于存储DNA或RNA测序数据在参考基因组上的比对结果。 SAM文件由多行文本组成&#xff0c;每一行代表一个比对结果。SAM文…

RustGUI学习(iced)之小部件(七):如何使用图像image部件来显示图片?

前言 本专栏是学习Rust的GUI库iced的合集,将介绍iced涉及的各个小部件分别介绍,最后会汇总为一个总的程序。 iced是RustGUI中比较强大的一个,目前处于发展中(即版本可能会改变),本专栏基于版本0.12.1. 概述 这是本专栏的第七篇,主要讲述图像Image部件的使用,会结合实例…