SSM学习笔记之Spring(一)

本文详细介绍了Spring框架的核心概念,包括Spring的概述、IoC(控制反转)和AOP(面向切面编程)。首先,阐述了Spring的作用、优点和体系结构。接着,深入讲解了IoC,通过创建Spring的第一个程序,展示了基于XML和注解的依赖注入(DI)方式,包括set注入、引用类型注入和自动注入。然后,探讨了基于注解的DI,使用了@Component、@Autowired、@Value等注解简化配置。最后,介绍了AOP的基本概念、好处以及AspectJ在Spring中的实现,包括不同类型的通知和切入点表达式。整个文章旨在帮助读者理解和掌握Spring的两大核心特性。
摘要由CSDN通过智能技术生成

Spring学习笔记之Spring概述、IoC控制反转、AOP面向切面编程

第一章 Spring概述

1.1 spring框架是什么?

spring: 出现是在2002左右,解决企业开发的难度。减轻对项目模块之间的管理,类和类之间的管理, 帮助开发人员创建对象,管理对象之间的关系。 spring核心技术 ioc , aop 。能实现模块之间,类之间的解耦合。
依赖:classa中使用classb的属性或者方法, 叫做classa依赖classb

1.2 spring优点

(1)轻量:Spring的所需要的jar包都非常小,一般1M以下,几百kb。核心功能所需要的jar包总共3M左右。Spring框架运行占有资源少,运行效率高,不依赖其他jar。
(2)针对接口编程,解耦合
(3)AOP 编程的支持:通过 Spring 提供的 AOP 功能,方便进行面向切面的编程,许多不容易用传统 OOP 实现的功能可以通过 AOP 轻松应付在 Spring 中,开发人员可以从繁杂的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。
(4)方便集成各种优秀框架:如Struts,Hibernate、 MyBatis等。

1.3 spring体系结构

图1-1  spring体系结构

第二章 IoC控制反转

IoC (Inversion of Control) : 控制反转, 是一个理论,概念,思想。把对象的创建,赋值,管理工作都交给代码之外的容器实现, 也就是对象的创建是有其它外部资源完成。
控制: 创建对象,对象的属性赋值,对象之间的关系管理。
反转: 把原来的开发人员管理,创建对象的权限转移给代码之外的容器实现。 由容器代替开发人员管理对象。创建对象,给属性赋值。
正转:由开发人员在代码中,使用new 构造方法创建对象, 开发人员主动管理对象。
容器:是一个服务器软件, 一个框架(spring)

2.1 spring的第一个程序

2.1.1 创建maven项目

在这里插入图片描述

2.1.2 引入maven依赖与插件

在这里插入图片描述
在这里插入图片描述

2.1.3 定义接口与实体类

接口:
在这里插入图片描述
实体类:
在这里插入图片描述

2.1.4 创建spring配置文件

在 src/main/resources/目录现创建一个 xml 文件, 文件名可以随意,但 Spring 建议的名称为 applicationContext.xml。
spring 配置中需要加入约束文件才能正常使用,约束文件是 xsd 扩展名。
在这里插入图片描述
bean :用于定义一个实例对象。一个实例对应一个 bean 元素。
id:该属性是 Bean 实例的唯一标识,程序通过 id 属性访问 。Bean: Bean 与 Bean 间的依赖关系也是通过 id 属性关联的。
class:指定该 Bean 所属的类,注意这里只能是类,不能是接口。

2.1.5 定义测试类

在这里插入图片描述

2.2 基于XML的DI

使用注解的步骤:
1.加入maven的依赖 spring-context ,在你加入spring-context的同时, 间接加入spring-aop的依赖。使用注解必须使用spring-aop依赖。
2.在类中加入spring的注解(多个不同功能的注解)。
3.在spring的配置文件中,加入一个组件扫描器的标签,说明注解在你的项目中的位置。

2.2.1 注入分类

bean 实例在调用无参构造器创建对象后,就要对 bean 对象的属性进行初始化。初始化是由容器自动完成的,称为注入。
根据注入方式的不同,常用的有两类: set 注入、构造注入

(1)set注入:set 注入也叫设值注入是指,通过 setter 方法传入被调用者的实例。这种注入方式简单、直观,因而在 Spring 的依赖注入中大量使用。

A:简单类型的set注入。
在这里插入图片描述
测试类结果:
在这里插入图片描述
B:引用类型
当指定 bean 的某属性值为另一 bean 的实例时,通过 ref 指定它们间的引用关系。 ref的值必须为某 bean 的 id 值。

在Student类中加入引用类型School:
在这里插入图片描述
对于其它 Bean 对象的引用,使用标签的 ref 属性
在这里插入图片描述
测试方法:
在这里插入图片描述

(2)构造注入:构造注入是指,在构造调用者实例的同时,完成被调用者的实例化。即,使用构造器设置依赖关系。
在这里插入图片描述
在这里插入图片描述

2.2.2 引用类型的自动注入

对于引用类型属性的注入,也可不在配置文件中显示的注入。可以通过为标签
设置 autowire 属性值,为引用类型属性进行隐式自动注入(默认是不自动注入引用类型属性)。
根据自动注入判断标准的不同,可以分为两种:
byName:根据名称自动注入
byType: 根据类型自动注入

(1)byName方式注入:当配置文件中被调用者 bean 的 id 值与代码中调用者 bean 类的属性名相同时,可使用byName 方式,让容器自动将被调用者 bean 注入给调用者 bean。容器是通过调用者的 bean类的属性名与配置文件的被调用者 bean 的 id 进行比较而实现自动注入的。
在这里插入图片描述
(2)byType方式注入:使用 byType 方式自动注入,要求:配置文件中被调用者 bean 的 class 属性指定的类,要与代码中调用者 bean 类的某引用类型属性类型同源。即要么相同,要么有 is-a 关系(子类,或是实现类)。但这样的同源的被调用 bean 只能有一个。多于一个,容器就不知该匹配哪一个了。
在这里插入图片描述

2.2.3 为应用指定多个Spring文件

在实际应用里,随着应用规模的增加,系统中 Bean 数量也大量增加,导致配置文件变得非常庞大、臃肿。为了避免这种情况的产生,提高配置文件的可读性与可维护性,可以将Spring 配置文件分解成多个配置文件。
包含关系的配置文件
多个配置文件中有一个总文件,总配置文件将各其它子文件通过引入。在 Java代码中只需要使用总配置文件对容器进行初始化即可。
在这里插入图片描述

也可使用通配符*。但,此时要求父配置文件名不能满足*所能匹配的格式,否则将出现循环递归包含。
在这里插入图片描述

2.3 基于注解的DI

对于 DI 使用注解,将不再需要在 Spring 配置文件中声明 bean 实例。Spring 中使用注解,需要在原有 Spring 运行环境基础上再做一些改变。需要在 Spring 配置文件中配置组件扫描器,用于在指定的基本包中扫描注解。
在这里插入图片描述
指定多个包的三种方式
1)使用多个 context:component-scan 指定不同的包路径:
在这里插入图片描述
2)指定 base-package 的值使用分隔符
分隔符可以使用逗号(,)分号(;)还可以使用空格,不建议使用空格。
在这里插入图片描述
3)base-package 是指定到父包名
base-package 的值表是基本包,容器启动会扫描包及其子包中的注解,当然也会扫描到子包下级的子包。所以 base-package 可以指定一个父包就可以。
不建议使用顶级的父包,扫描的路径比较多,导致容器启动时间变慢。指定到目标包和合适的。也就是注解所在包全路径。例如注解的类在 com.bjpowernode.beans 包中。
在这里插入图片描述

2.3.1 定义 Bean 的注解@Component

需要在类上使用注解@Component,该注解的 value 属性用于指定该 bean 的 id 值。
如下图:
在这里插入图片描述
另外, Spring 还提供了 3 个创建对象的注解:
➢ @Repository 用于对 DAO 实现类进行注解
➢ @Service 用于对 Service 实现类进行注解
➢ @Controller 用于对 Controller 实现类进行注解

这三个注解与@Component 都可以创建对象,但这三个注解还有其他的含义, @Service创建业务层对象,业务层对象可以加入事务功能, @Controller 注解创建的对象可以作为处理器接收用户的请求。
@Repository, @Service, @Controller 是对@Component 注解的细化,标注不同层的对象。 即持久层对象,业务层对象,控制层对象。
@Component 不指定 value 属性, bean 的 id 是类名的首字母小写。

2.3.2 简单类型属性注入@Value

需要在属性上使用注解@Value,该注解的 value 属性用于指定要注入的值。**使用该注解完成属性注入时,类中无需 setter。**当然,若属性有 setter,则也可将其加到 setter 上。
在这里插入图片描述

2.3.3 byType 自动注入@Autowired

需要在引用属性上使用注解@Autowired,该注解默认使用按类型自动装配 Bean 的方式。使用该注解完成属性注入时,类中无需 setter。当然,若属性有 setter,则也可将其加到 setter 上。
在这里插入图片描述
在这里插入图片描述

2.3.4 byName 自动注入@Autowired 与@Qualifier

需要在引用属性上联合使用注解@Autowired 与@Qualifier。 @Qualifier 的 value 属性用于指定要匹配的 Bean 的 id 值。 类中无需 set 方法,也可加到 set 方法上。
注意:
@Autowired 还有一个属性 required,默认值为 true,表示当匹配失败后,会终止程序运行。若将其值设置为 false,则匹配失败,将被忽略,未匹配的属性值为 null。
在这里插入图片描述
在这里插入图片描述

2.3.5 JDK 注解@Resource 自动注入

Spring提供了对 jdk中**@Resource注解**的支持。@Resource 注解既可以按名称匹配Bean,也可以按类型匹配 Bean。 默认是按名称注入。 使用该注解,要求 JDK 必须是 6 及以上版本。@Resource 可在属性上,也可在 set 方法上。

(1)byType 注入引用类型属性
@Resource来自jdk中的注解,spring框架提供了对这个注解的功能支持,可以使用它给引用类型赋值使用的也是自动注入原理,支持byName,byType,默认是byName
在这里插入图片描述
在这里插入图片描述
这里加一点个人理解,@Resource默认是byName,在无法找到对应的bean的id时就会继续去找对应的class。

2.4 注解与 XML 的对比

注解优点是:
⚫ 方便
⚫ 直观
⚫ 高效(代码少,没有配置文件的书写那么复杂)。
其弊端也显而易见:以硬编码的方式写入到 Java 代码中,修改是需要重新编译代码的。
XML 方式优点是:
⚫ 配置和代码是分离的
⚫ 在 xml 中做修改,无需编译代码,只需重启服务器即可将新的配置加载。
xml 的缺点是:编写麻烦,效率低,大型项目过于复杂。

第三章 AOP 面向切面编程

3.1 不使用aop的开发方式

先定义好接口与一个实现类,该实现类中除了要实现接口中的方法外,还要再写两个非业务方法。非业务方法也称为交叉业务逻辑:
➢ doLog():用于事务处理
➢ doTrans():用于日志处理
然后,再使接口方法调用它们。接口方法也称为主业务逻辑。

接口SomeService:
在这里插入图片描述
接口的实现类SomeServiceImpl:
在这里插入图片描述
非业务方法doLog和doTrans:
在这里插入图片描述
可以采用动态代理方式。在不修改主业务逻辑的前提下,扩展和增强其功能。
在这里插入图片描述

在测试类中测试方法,结果如下图:
在这里插入图片描述

3.2 AOP概述

怎么理解面向切面编程 ?
1)需要在分析项目功能时,找出切面。
2)合理的安排切面的执行时间(在目标方法前, 还是目标方法后)
3)合理的安全切面执行的位置,在哪个类,哪个方法增加增强功能

AOP(Aspect Orient Programming),面向切面编程。面向切面编程是从动态角度考虑程序运行过程。 AOP 底层,就是采用动态代理模式实现的。采用了两种代理:JDK 的动态代理,与 CGLIB 的动态代理,AOP可以看作动态代理的规范化与标准化。

面向切面编程,就是将交叉业务逻辑封装成切面,利用 AOP 容器的功能将切面织入到 主业务逻辑中。所谓交叉业务逻辑是指,通用的、与主业务逻辑无关的代码,如安全检查、 事务、日志、缓存等。 若不使用 AOP,则会出现代码纠缠,即交叉业务逻辑与主业务逻辑混合在一起。这样, 会使主业务逻辑变的混杂不清。

例如,转账,在真正转账业务逻辑前后,需要权限控制、日志记录、加载事务、结束事 务等交叉业务逻辑,而这些业务逻辑与主业务逻辑间并无直接关系。但,它们的代码量所占 比重能达到总代码量的一半甚至还多。它们的存在,不仅产生了大量的“冗余”代码,还大 大干扰了主业务逻辑—转账。

3.3 面向切面编程对有什么好处?

1.减少重复;
2.专注业务;

3.4 AOP 编程术语

(1) 切面(Aspect)
切面泛指交叉业务逻辑。上例中的事务处理、日志处理就可以理解为切面。常用的切面是通知(Advice)。实际就是对主业务逻辑的一种增强。

(2) 连接点(JoinPoint)
连接点指可以被切面织入的具体方法。通常业务接口中的方法均为连接点。

(3) 切入点(Pointcut)

切入点指声明的一个或多个连接点的集合。通过切入点指定一组方法。被标记为 final 的方法是不能作为连接点与切入点的。因为最终的是不能被修改的,不能被增强的。

(4) 目标对象(Target)
目 标 对 象 指 将 要 被 增 强 的 对 象 。 即 包 含 主 业 务 逻 辑 的 类 的 对 象 。 上 例 中 的StudentServiceImpl 的对象若被增强,则该类称为目标类,该类对象称为目标对象。当然,不被增强,也就无所谓目标不目标了。

(5) 通知(Advice)
通知表示切面的执行时间, Advice 也叫增强。 上例中的MyInvocationHandler 就可以理解为是一种通知。换个角度来说, 通知定义了增强代码切入到目标代码的时间点,是目标方法执行之前执行,还是之后执行等。通知类型不同,切入时间不同。切入点定义切入的位置,通知定义切入的时间。

3.5 AspectJ 对 AOP 的实现

AOP的技术实现框架:
Spring:Spring的AOP实现较为笨重,一般用在事务处理。
aspectJ:一个开源,专门做AOP的框架,隶属于Eclipse基金会。
在 Spring 中使用 AOP 开发时,一般使用 AspectJ 的实现方式。
aspectJ框架实现AOP有两种方式:
(1) 使用xml配置文件,一般用于配置全局事务。
(2) 使用注解。一般在项目开发中使用这种方式。

3.5.1 AspectJ 的通知类型

AspectJ 中常用的通知有五种类型:
(1)前置通知
(2)后置通知
(3)环绕通知
(4)异常通知
(5)最终通知

3.5.2 AspectJ 的切入点表达式

AspectJ 定义了专门的表达式用于指定切入点。表达式的原型是:
在这里插入图片描述
解释:
modifiers-pattern] 访问权限类型
ret-type-pattern 返回值类型
declaring-type-pattern 包名类名
name-pattern(param-pattern) 方法名(参数类型和参数个数)
throws-pattern 抛出异常类型
?表示可选的部分
以上表达式共 4 个部分。
execution(访问权限 方法返回值 方法声明(参数) 异常类型)
切入点表达式要匹配的对象就是目标方法的方法名。所以, execution 表达式中明显就是方法的签名。 注意,表达式中黑色文字表示可省略部分,各部分间用空格分开。在其中可以使用以下符号:
*:0至多个任意字符。
…: 用在方法参数中,表示任意多个参数;用在包名后,表示当前包及其子包。
+:用在类名后,表示当前类及其子类;用在接口名后,表示当前接口及其实现类。

3.5.3 AspectJ 的开发环境

(1) maven依赖
在这里插入图片描述
在这里插入图片描述
(2) 引入AOP约束
在 AspectJ 实现 AOP 时,要引入 AOP 的约束。配置文件中使用的 AOP 约束中的标签,均是 AspectJ 框架使用的,而非 Spring 框架本身在实现 AOP 时使用的。
AspectJ 对于 AOP 的实现有注解和配置文件两种方式,常用是注解方式

3.5.4 AspectJ 基于注解的 AOP 实现

(1) 实现步骤
A、Step1:定义业务接口与实现类

在这里插入图片描述
在这里插入图片描述
B、Step2:定义切面类
在这里插入图片描述
C、 Step3: 声明目标对象切面类对象
在这里插入图片描述
D、 Step4:注册 AspectJ 的自动代理
在这里插入图片描述
aop:aspectj-autoproxy/的底层是由 AnnotationAwareAspectJAutoProxyCreator 实现的。
从其类名就可看出,是基于 AspectJ 的注解适配自动代理生成器。
其工作原理是, aop:aspectj-autoproxy/通过扫描找到@Aspect 定义的切面类,再由切面类根据切入点找到目标类的目标方法,再由通知类型找到切入的时间点。
E、 Step5:测试类中使用目标对象的 id
在这里插入图片描述
(2) [掌握]@Before 前置通知-方法有 JoinPoint 参数
在目标方法执行之前执行。被注解为前置通知的方法,可以包含一个 JoinPoint 类型参数。该类型的对象本身就是切入点表达式。通过该参数,可获取切入点表达式、方法签名、目标对象等。
不光前置通知的方法,可以包含一个 JoinPoint 类型参数,所有的通知方法均可包含该参数。
在这里插入图片描述
(3) [掌握]@AfterReturning 后置通知-注解有 returning 属性
在目标方法执行之后执行。由于是目标方法之后执行,所以可以获取到目标方法的返回值。该注解的 returning 属性就是用于指定接收方法返回值的变量名的。所以,被注解为后置通知的方法,除了可以包含 JoinPoint 参数外,还可以包含用于接收返回值的变量。该变
量最好为 Object 类型,因为目标方法的返回值可能是任何类型。

在实现@AfterReturning 后置通知-注解之前,对于后置通知的位置,属性等等的描述如下图:
在这里插入图片描述

接口增加方法:
在这里插入图片描述
实现方法:
在这里插入图片描述
定义切面:
在这里插入图片描述
(4) @Around 环绕通知-增强方法有 ProceedingJoinPoint
参数

在目标方法执行之前之后执行。被注解为环绕增强的方法要有返回值, Object 类型。并且方法可以包含一个 ProceedingJoinPoint 类型的参数。**接口 ProceedingJoinPoint 其有一个proceed()方法,用于执行目标方法。若目标方法有返回值,则该方法的返回值就是目标方法的返回值。**最后,环绕增强方法将其返回值返回。该增强方法实际是拦截了目标方法的执行。
在实现@ @Around 环绕通知之前,对于环绕通知的位置,属性等等的描述如下图:
在这里插入图片描述
接口增加方法:
在这里插入图片描述
实现接口增加方法:
在这里插入图片描述
定义切面:
在这里插入图片描述

最后补充一句,在环绕通知里面,返回值的结果是可以进行修改的,在上图中设置初始返回值为doFirst,在切面最后设置返回值结果为hello world,测试方法中最终返回值结果如下:
在这里插入图片描述
(5) [了解]@AfterThrowing 异常通知-注解中有 throwing 属性
在目标方法抛出异常后执行。该注解的 throwing 属性用于指定所发生的异常类对象。当然,被注解为异常通知的方法可以包含一个参数 Throwable,参数名称为 throwing 指定的名称,表示发生的异常对象。

在实现@AfterThrowing 异常通知之前,对于环绕通知的位置,属性等等的描述如下图:
在这里插入图片描述
增加业务方法:
在这里插入图片描述

方法实现:
在这里插入图片描述
定义切面:
在这里插入图片描述
(6) [了解]@After 最终通知
无论目标方法是否抛出异常,该增强均会被执行。
在实现@After最终通知之前,对于环绕通知的位置,属性等等的描述如下图:
在这里插入图片描述
增加业务方法:
在这里插入图片描述
实现方法:
在这里插入图片描述
定义切面:
在这里插入图片描述
(7) @Pointcut 定义切入点
当较多的通知增强方法使用相同的 execution 切入点表达式时,编写、维护均较为麻烦。AspectJ 提供了@Pointcut 注解,用于定义 execution 切入点表达式。
其用法是,将@Pointcut 注解在一个方法之上,以后所有的 execution 的 value 属性值均可使用该方法名作为切入点。代表的就是@Pointcut 定义的切入点。这个使用@Pointcut 注解的方法一般使用 private 的标识方法,即没有实际作用的方法。
在这里插入图片描述

3.5.5 当目标类没有接口,使用cglib动态代理,spirng框架会自动应用cglib

目标类:
在这里插入图片描述
切面类:
在这里插入图片描述
测试类:
在这里插入图片描述
测试结果:
proxy:com.bjpowernode.ba07.impl.SomeServiceImpl E n h a n c e r B y S p r i n g C G L I B EnhancerBySpringCGLIB EnhancerBySpringCGLIB8ddcbfae
由此可见当目标类没有接口,使用cglib动态代理,spirng框架会自动应用cglib
在这里插入图片描述

3.5.5 当目标类有接口,使用cglib动态代理

只需要在applicatioanContext中设置aop:aspectj-autoproxy proxy-target-class="true"
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值