Spring入门

spring入门

spring一开始创建单列bean放到容器去管理,这样使项目运行速度快,且提前自检,避免运行时报错的问题的线上问题,避免了内存不足时的频繁gc操作。我们面向接口去编程,高内聚,低耦合.

轻量型的框架

spring的有什么好处:

1.所有的bean以单例形式存在于容器中,避免大量对象重复创建,可能造成jvm内存吃紧,频繁gc。

2.程序启动后,初始化单例bean,将所有构建过程的异常在启动时就暴露出来,而不是运行时,相对更加安全。自检功能

3 .缓存了所有的单例bean,启动过程就进行了预热,运行时不用进行对象创建,效率更高。

4.容器管理bean的生命周期,面向接口去编程时,扩展性,维护性更好,高内聚,低耦合。

Spring容器的启动流程:

(1)初始化Spring容器,注册内置的BeanPostProcessor的BeanDefinition到容器中:

① 实例化BeanFactory【DefaultListableBeanFactory】工厂,用于生成Bean对象
② 实例化BeanDefinitionReader注解配置读取器,用于对特定注解(如@Service、@Repository)的类进行读取转化成 BeanDefinition 对象,(BeanDefinition 是 Spring 中极其重要的一个概念,它存储了 bean 对象的所有特征信息,如是否单例,是否懒加载,factoryBeanName 等)
③ 实例化ClassPathBeanDefinitionScanner路径扫描器,用于对指定的包目录进行扫描查找 bean 对象
(2)将配置类的BeanDefinition注册到容器中:

(3)调用refresh()方法刷新容器:

① prepareRefresh()刷新前的预处理:
② obtainFreshBeanFactory():获取在容器初始化时创建的BeanFactory:
③ prepareBeanFactory(beanFactory):BeanFactory的预处理工作,向容器中添加一些组件:
④ postProcessBeanFactory(beanFactory):子类重写该方法,可以实现在BeanFactory创建并预处理完成以后做进一步的设置
⑤ invokeBeanFactoryPostProcessors(beanFactory):在BeanFactory标准初始化之后执行BeanFactoryPostProcessor的方法,即BeanFactory的后置处理器:
⑥ registerBeanPostProcessors(beanFactory):向容器中注册Bean的后置处理器BeanPostProcessor,它的主要作用是干预Spring初始化bean的流程,从而完成代理、自动注入、循环依赖等功能
⑦ initMessageSource():初始化MessageSource组件,主要用于做国际化功能,消息绑定与消息解析:
⑧ initApplicationEventMulticaster():初始化事件派发器,在注册监听器时会用到:
⑨ onRefresh():留给子容器、子类重写这个方法,在容器刷新的时候可以自定义逻辑
⑩ registerListeners():注册监听器:将容器中所有的ApplicationListener注册到事件派发器中,并派发之前步骤产生的事件:
⑪ finishBeanFactoryInitialization(beanFactory):初始化所有剩下的单实例bean,核心方法是preInstantiateSingletons(),会调用getBean()方法创建对象;
⑫ finishRefresh():发布BeanFactory容器刷新完成事件:

第一章概述:

1 . 容器:

可以管理对象的声明周期,对象与对象之间的依赖关系。把很多bean放在一个容器里。

2 . POJO:简单的java对象

没有继承类,没有接口,没有其他框架侵入的java对象,没有业务方法,没有connection之类的方法(实际就是普通的javaBeans)

(1)javaBeans:javabean更多地作为值传递参数

所有属性为private。

这个类必须有一个公共的缺省构造函数。即是提供无参数的构造器。

这个类的属性使用getter和setter来访问,其他方法遵从标准命名规范。

这个类应是可序列化的。实现serializable接口。

注意:javaBeans一定是个POJO,但是POJO不一定是javaBeans。POJO类和Bean均用于定义Java对象,以提高其可读性和可重用性。POJO没有其他限制,而bean是具有某些限制的特殊POJO。

(2)springBeans:

BeanFactory接口提供了一种高级的配置机制,能够管理任何类型的对象。 ApplicationContext是BeanFactory的子接口。 它对BeanFactory进行了补充:

用处不同:传统javabean更多地作为值传递参数,而spring中的bean用处几乎无处不在,任何组件都可以被称为bean。

写法不同:传统javabean作为值对象,要求每个属性都提供getter和setter方法;但spring中的bean只需为接受设值注入的属性提供setter方法。

生命周期不同:传统javabean作为值对象传递,不接受任何容器管理其生命周期;spring中的bean有spring管理其生命周期行为。

(3)在maven中引入spring的相关依赖:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-geUm4TEc-1681790399036)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665323000297.png)]

3 .IOC容器:

在spring中,我们的bean不由我们去构造,也不用我们去管理,都交给容器来完成。(spring把很多java类对象都按照bean的方式建立,不需要自己去创建这些对象,也不用自己去管理)这个就是控制反转(ioc)。通过控制反转让我们的容器帮我们创建bean,管理bean。

为什么要把这种方式叫做控制反转呢?

(1) 软件系统在没有引入IoC容器之前,对象A依赖对象B,那么A对象在实例化或者运行到某一点的时候,自己必须主动创建对象

B或者使用已经创建好的对象B,其中不管是创建还是使用已创建的对象B,控制权都在我们自己手上。

(2)如果软件系统引入了Ioc容器之后,对象A和对象B之间失去了直接联系,所以,当对象A实例化和运行时,如果需要对象B的

话,IoC容器会主动创建一个对象B注入到对象A所需要的地方。

(3)通过前面的对比,可以看到对象A获得依赖对象B的过程,由主动行为变成了被动行为,即把创建对象交给了IoC容器处理,控

制权颠倒过来了,这就是控制反转的由来!

4 . 元数据:

在spring中,如何让容器创建bean?(比如要按照我的方式做蛋糕,那么就需要一份我做蛋糕的配方才能做)让容器创建我们需要的bean,则需要元数据来创建bean。元数据就是这个配方

(1)配置元数据:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qrtfc0fT-1681790399037)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665325492297.png)]

5 . 实例化容器:

容器通过反射找到对应类,拿到对应类对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GAl0IMep-1681790399037)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665325950994.png)]

6 . bean的概述:

(1)bean的命名:

每个bean都有一个或多个标识符,这些标识符在承载bean的容器里必须是唯一的,bean通常只用一个标识符

例如给userDao的bean起名:起了两个名字:dao,dao2

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9kCCGrFS-1681790399038)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665385019991.png)]

实例化容器:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lQgBAANG-1681790399038)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665385079714.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CtInAkd5-1681790399038)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665385112010.png)]

我们通常采用的命名跟java类的命名相同采用驼峰式命名。

当我们没有命名,spring默认会为我们注入bean:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M5ZfPDvS-1681790399038)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665385360108.png)]

此时我们通过反射获取:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uox4vHx1-1681790399038)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665385417388.png)]

(2)bean的别名:

给bean的名字起哥别名,我们也可以通过别名拿到我们需要的bean。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r0gEDJXD-1681790399039)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665385617828.png)]

(3)实例化bean(就是new一个bean):

a . 使用构造器实例化:

普通的new一个bean,就是使用无参构造器实例化。

b. 静态工厂实例化:

在UserService中:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hhglHXs5-1681790399039)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665389250979.png)]

在xml文件中:表示new的bean是根据create方法中实行的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7TQEm8g6-1681790399039)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665389265820.png)]

我们使用slf4j日志来进行打印信息:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1ifwoXwU-1681790399039)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665389671349.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-79OYJ5UM-1681790399040)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665389689154.png)]

具体实现类:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IiTAXCnP-1681790399040)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665389636314.png)]

c . 使用实例工厂方法实例化:

我们在创建一个实例方法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-koqyGRt0-1681790399040)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665390205090.png)]

xml文件配置:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-orZj2FkY-1681790399041)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665391440812.png)]

具体实现类:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6XITgKDS-1681790399041)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665391709755.png)]

7 . 依赖注入:(重点)

依赖注入(DI)是一个【过程】(目前可以理解为给成员变量赋值的过程),在此过程中,对象仅通过【构造函数参数】、【工厂方法参数】等来确定它们的依赖项。 然后容器在创建bean时注入这些依赖项。 从根本上说,这个过程与bean本身相反(因此得名“控制反转”)。

例如:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N1eOOVtO-1681790399041)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665392742629.png)]

由图:我们正常创建c对象,发现了以上规律:先创建b对象后,创建a对象需要注入b对象才能创建,创建c需要注入a都对象才能创建。创建顺序是:b,a,c

那么到spring容器时,它不可能知道这个规律,它是直接创建c对象,发现要创建a,去创建a,创建a后又发现要先创建b,去创建b。创建顺序是:c,a,b

容器的创建方向与我们手动创建的方向相反,是个逆操作,这就是控制反转。

对于依赖注入有两种方式:

构造注入:构造器提供有参构造,往里边注入,本质上是使用构造器给成员变量赋值。

setter注入:通过setter方法往里边注入,本质上是使用set方法给成员变量赋值。

(1)使用构造器依赖注入:

已知UserService类:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-grwQTcj7-1681790399041)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665398108387.png)]

xml配置:在UserService中有UserDao和AddressDao两个成员,并有构造器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jRL3lLZg-1681790399042)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665397681239.png)]

具体实现类:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AJff1WSk-1681790399042)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665395976216.png)]

我们通过debug发现了spring容器在通过创建userService的bean时,已经创建好了另外两个bean

如果我们要明确的把参数赋值给引用的bean:

通过构造器得知:userDao在第0个,addressDao在第1个

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2YkKYYLx-1681790399042)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665398627207.png)]

所以我们把userdao赋值给第0个参数,addressDao赋值给第0个参数,这样也不会报错,但是必须要注意参数的洗标位置,否则报错。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IPXTHu30-1681790399042)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665398608984.png)]

我们也可以通过name注入:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fh94LMjo-1681790399043)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665398860065.png)]

(2)setter注入:

已知UserService类中的userdao和addressdao都有他们各自的setter方法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WJMJtAc7-1681790399043)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665399376172.png)]

在xml中通过setter注入:通过spring容器创建了UserService的bean对象,再通过该对象调用setter方法创建了userdao和addressdao的对象。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OTCVycRd-1681790399043)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665399568256.png)]

具体实现:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qnilfVT8-1681790399044)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665399635072.png)]

(3)两种选择的注意事项:

一般情况下,我们对于【强制性依赖项】使用构造函数,对于【可选依赖项】使用setter方法注入,这是一个很好的经验法则。 注意,在setter方法上使用【@Required】注解可以使属性成为必需依赖项。

(4)注入配置重点细节:

已知user类的getset,构造器,toString方法都设置完成:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wrUFUGnR-1681790399044)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665403593584.png)]

xml配置:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qHUHk62a-1681790399044)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665403641196.png)]

具体实现类:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ulUWVYEH-1681790399044)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665403681932.png)]

8 . null和空串的表示:

email为空串:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-530rItYM-1681790399045)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665406782331.png)]

address的值为null:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DGS8zkvr-1681790399045)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665406807733.png)]

9 . p命名空间和c命名空间:

p命名空间:给带p命名空间的xml(给property注入)

格式: p: + property属性的名字

没有用p命名空间时:我们再property属性赋值:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zdxbCSgK-1681790399045)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665407652056.png)]

引入:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vPGigOjE-1681790399046)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665407741590.png)]

用上p命名空间后:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yojSh0Vm-1681790399046)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665407562137.png)]

c命名空间:给带构造器的注入(c打头)

格式: c: + 构造器参数的名字

引入:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SRHzzW3a-1681790399047)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665408089518.png)]

没有用c命名空间时:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Eh81QkEe-1681790399047)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665408198673.png)]

使用c命名空间后:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dlaqg79Q-1681790399047)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665408211550.png)]

按照构造器参数下标:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KYFsktPD-1681790399047)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665408236492.png)]

10 . 延迟初始化的 Bean:(懒加载)

延迟初始化的bean告诉IoC容器在【第一次请求】时创建bean实例,而不是在启动时。

Address类:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c6HtJ8k1-1681790399048)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665409045003.png)]

xml设置:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z87qnYcL-1681790399048)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665409012540.png)]

启动测试类:显示结果,表示已启动就初始化了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A9g5iuRs-1681790399048)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665409077410.png)]

我们设置为true:没有输出,表示启动时没有初始化构造器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tuwt95kj-1681790399048)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665409134764.png)]

11 . 自动装配(重点):

手动装配:自己手写指定依赖项

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v2OwE2mk-1681790399049)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665409599196.png)]

(1) byName:

通过名字查找, Spring寻找与需要自动连接的属性同名的bean。 例如,如果一个beanDifination被设置为按名称自动装配,并且它包含一个“master”属性(也就是说,它有一个“setMaster(…)”方法),Spring会寻找一个名为“master”的beanDifination并使用它来设置属性。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8Wba7OWJ-1681790399049)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665415866116.png)]

具体实现:可以看出address没有为null

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eBFc2GMv-1681790399049)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665414819038.png)]

(2)byType:根据类型来自动装配

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f2jEsh0N-1681790399049)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665416254493.png)]

(3)constructor:

类似于’ byType ',但适用于构造函数参数。 如果容器中没有一个构造函数参数类型的bean,则会引发致命错误。

首先User类中创建有参和无参构造器:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CcFbgKvD-1681790399050)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665416744791.png)]

xml配置:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cmipuWVJ-1681790399050)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665416775699.png)]

具体实现类:address不为null

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iSXZyEsW-1681790399050)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665416823823.png)]

如果我们的Address是一个集合类型,且相应的getset方法都已设置:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pxbihx5r-1681790399050)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665417273771.png)]

xml文件配置:我们配置多个Address的bean

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3KNP6oDY-1681790399051)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665417316328.png)]

具体实现:将两个address的bean的内容存入List中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ms4Nop5F-1681790399051)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665417358443.png)]

12 . 循环依赖:(重点)

循环依赖:如下图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wHi057pj-1681790399051)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665417801466.png)]

填充就是容器里找到了对应的bean时,调用对应set方法设置属性的值。

途中的A,B都是半成品,就是创建完成了初始化了,但是内部没有赋值。

所以A,B他们都是可以拿来引用的,A需要B时是可以使用B的,B需要A时是可以使用B的,不会造成死循环。

(1)解决循环依赖的问题:加缓存(二级缓存)

只要A一创建,我们就将A放到缓存(二级缓存)中,填充A的成员属性时发现需要依赖B,就先去容器查找有没有B(先去一级缓存找,一级缓存存储的完成品的bean,完成品不仅构造了对象,而且属性的值也设置填充完成),没有找到就创建B(半成品,放到二级缓存),B创建完成进行填充成员属性,结果发现填充需要依赖A对象,于是又去容器找(先去一级缓存找完成品的A),没有找到,就去二级缓存找,找到了半成品的A对象,通过A,B完成了对成员属性的填充,B就成了完成品,把二级缓存的半成品B删除,将完成品的B存入一级缓存。此时A填充成员属性再去容器找B时,在一级缓存找到了B,完成了成员属性的填充。A就成了完成品,删除二级缓存的半成品A,将完成品的A存入一级缓存。

模拟可解决的循环依赖:

创建A,B类:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lCd6YysB-1681790399052)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665420102819.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z7ahIP6t-1681790399052)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665420113207.png)]

xml配置:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tLw7rFON-1681790399052)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665420139885.png)]

具体实现类:显示A,B的对象都打印出来

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wIRniQP8-1681790399052)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665420183048.png)]

若我们在A,B中设置构造器:

构造A只能通过B来构造:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ahzXAbRY-1681790399052)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665420434251.png)]

构造B只能通过A来构造:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uNIVfHzQ-1681790399052)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665420495291.png)]

xml配置:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dvXZt7Eg-1681790399053)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665420601749.png)]

我们实现类不变,运行报错。这种错误的产生原因是创建A时,A还没有创建好就需要一个B,而创建B还没创建好就需要一个A,造成死循环。

13 . Bean的作用域:

(1)单例的作用域(SingleTon):

只管理一个单例的bean,只管理一个共享数据, 容器只管理【一个bean的共享实例】,所有对具有一个或多个标识符的bean的请求都将导致Spring容器返回一个特定唯一的bean实例。(当我们调用getBean或者需要注入bean的时候,所获取到的bean都是同一个)

注意:

【Spring的单例bean概念不同于设计模式书中定义的单例模式】。 单例设计模式对对象的作用域进行硬编码(spring容器里只能有一个实例,你不能再创建其他的实例),使得每个ClassLoader只创建一个特定类的实例(这样导致我们不能new实例,也不能用其他方法去创建实例,只能通getInstance(),getSingleTon()拿到容器存在的那个实例)。

也就是说spring容器里只有一个实例,你不能再创建新的实例,你取实例也只能拿到容器里这个实例。

如定义一个单例的bean:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rgd4JNAR-1681790399053)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665475447240.png)]

(2)原型作用域:

非单例原型作用域导致【每次对特定bean发出请求时都要创建一个新的bean实例】。 也就是说,该bean被注入到另一个bean中,或者您通过容器上的getBean()方法调用请求它,都会创建一个新的bean。 作为一条规则,您应该对所有有状态bean(内部有自己独特的数据,每次操作时会随着状态数据会改变)使用原型作用域,对无状态bean使用单例作用域。

Spring并【不管理原型bean的完整生命周期】。 容器实例化、配置和组装一个原型对象,并将其传递给客户端,而不需要进一步记录该原型实例,不会缓存,不会管理他的后续生命周期****(原型被容器生成,但是原型的养,销毁死亡容器不管)****。 因此,尽管初始化生命周期回调方法在所有对象上都被调用但在原型的情况下,配置的销毁生命周期回调不会被调用。而单例bean容器会将它的一生都管理(亲儿子)。

定义原型bean:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dWGGvlwl-1681790399053)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665476827973.png)]

证明:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tD96oFBA-1681790399053)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665477594012.png)]

由此可知,两次拿到的bean都是容器里的同一个bean

如果我们再xml配置加上:使其变成原型作用域

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VlIx8jw9-1681790399053)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665477700991.png)]

那么我们再运行测试类时,发现不是true,而是false了,说明拿到的不是同一个bean。

14 . 生命周期回调:

Address类:实现相关接口方法,实现destory()和afterPropertiesSet()方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X7B8TuF8-1681790399053)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665481544957.png)]

xml文件配置:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H9jV5r4E-1681790399054)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665481595637.png)]

实现类:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iUcubFJL-1681790399054)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665481696368.png)]

Address类中空参构造器在被创建bean时调用输出了:

address is create

之后创建bean后,调用set方法对bean进行填充,取名为ccs,输出了:

set name

在将bean填充后才会开始调用afterPropertiesSet方法,输出了:

afterPropertiesSet

我们一般都是在afterPropertiesSet()内进行其他的操作(对bean的修改等)

最后调用destory():销毁

destory

生命周期流程总结:

创建bean,属性填充,afterPropertiesSet (类似初始化操作), 我们对bean的使用操作,destory(销毁)

15 . 配置和注解实现生命周期:

注解@PostConstruct:调用构造器初始化后执行它注解的方法

注解@PreDestory:要销毁前执行它注解的方法

引入依赖:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lAW2WNrv-1681790399054)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665484314633.png)]

已知A类中:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dE9u21KW-1681790399054)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665484619190.png)]

xml文件配置:引入后,才能启动注解的功能,且A的bean制定了初始化和销毁的方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bWTgFCEQ-1681790399054)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665484396711.png)]

测试类:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JDqzBRaP-1681790399054)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665484663838.png)]

从结果可以看出,在拿到A的bean后,注解@PostConstruct就立刻调用了init2()方法,之后才是bean对象按照xml的指示调用init()方法,而再要执行销毁destory()前,@PreDestory注解调用了destory2(),最后再执行的销毁方法。

16 . aware扩展接口:

已知c类:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XWSKT3AE-1681790399055)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665489681987.png)]

xml配置:只是定义了一个bean标签,其他的bean的名字。bean填充的内容都没写:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cZSMtpCJ-1681790399055)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665489741253.png)]

具体实现类:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N55A7PDM-1681790399055)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665489795626.png)]

因为bean标签什么都没指定,bean创建好后需要填充它的成员属性的值,C类实现了BeanNameAware接口,实现了setBeanName方法,在容器创建bean后,就会将创建好的bean去调用setBeanName方法去设置成员属性name的值,同理C类也实现了ApplicationContextAware接口,实现了setApplicationContext方法,在bean创建好后也会去调用该方法设置成员属性applicationContext的值,所以我们在测试类输出后,能显示看到各个成员属性的值不为null。

其实就是实现了该接口的方法,通过该方法,将bean统一的按照该方法来进行填充注入成员属性。

除了“ApplicationContextAware”和“BeanNameAware”,spring提供了一个广泛的“aware”回调接口,让bean指示容器,他们需要一定【基础设施】的依赖。 作为一般规则,名称指示了所需依赖项的类型。 下表总结了一些最重要的“Aware”接口:

命名依赖注入
ApplicationContextAwareApplicationContext注入bean当中
ApplicationEventPublisherAwareApplicationEventPublisherAware注入bean当中
BeanClassLoaderAware将类加载器用于装入bean类
BeanFactoryAwareBeanFactory注入bean当中
BeanNameAware将bean的名称注入bean中
ResourceLoaderAware配置了用于访问资源的加载器
ServletConfigAware当前的’ ServletConfig '容器运行。 仅在web感知的Spring ’ ApplicationContext '中有效。
ServletContextAware当前运行容器的“ServletContext”。 仅在web感知的Spring ’ ApplicationContext '中有效。

再次注意,使用这些接口将您的代码与Spring API绑定在一起,而不是遵循控制反转风格。 因此,我们将它们推荐给需要对容器进行编程访问的基础架构bean

总结:实现了aware相关的接口,ioc容器不在遵循ioc风格,意思就是不在遵循按需初始化并注入依赖,而是特定的条件下在统一的地方统一注入

16 . 基于注解的容器配置:(重要)

(1)autowired注解:自动装配(有byType的部分功能)

已知的类信息:

Boy:有两个构造器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zW7mNm7k-1681790399055)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665493521967.png)]

Pet:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BcRaYTnf-1681790399055)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665493338533.png)]

Cat:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CPU0v0gb-1681790399056)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665493368471.png)]

Dog:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wxrp4g9W-1681790399056)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665493358567.png)]

此时我们在xml配置上:显示报错,这是因为Boy的初始化创建bean不知道调用哪个构造器构造Boy的bean。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TbONJQzt-1681790399056)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665493397709.png)]

此时我们在其中一个构造器上加上注解:@Autowired,那么spring就会知道调用这个构造器[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zPJjpuSm-1681790399056)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665493628314.png)]

此时xml也不报错,测试正常运行。

@Autowired也可以注在方法上:容器创建好bean后就会自动调用该方法填充成员属性

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YjEDUpsI-1681790399056)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665494005226.png)]

用的最多的:

将@Autowired用在字段上

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fgcgpuau-1681790399056)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665495377041.png)]

然后我们测试类显示:各属性都有值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sJ8mfxNa-1681790399057)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665495412971.png)]

总结:用上@Autowired,我们不需要在xml里明确指定bean的name,使用的构造器,setter方法,只需要在java类中给我们需要的部分加上这个注释就可完成功能。

在map的使用:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R0ybppAh-1681790399057)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665499601534.png)]

xml:有很多宠物狗

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LCNizpNP-1681790399057)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665499619920.png)]

具体实现:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pEJCEsej-1681790399057)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665499666274.png)]

注意:

:默认情况下,当给定注入点没有可用的匹配候选bean时,自动装配将失败。 对于声明的数组、集合或映射,至少需要一个匹配元素。

如果我们加上注解@Autowired给某个字段,但是xml中没有该字段时,如:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lsmviLT8-1681790399057)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665499754116.png)]

xml中没有宠物相关的bean,或者有很多宠物相关的bean

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6GDJeSaS-1681790399057)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665499785411.png)]

那么测试时就会注入失败报错,因为它找不到究竟是要哪个注入,我们可以:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3VankDb4-1681790399057)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665500994346.png)]

加上该括号信息后,按照默认注入,默认行为是将带注解的方法和字段视为指示所需的依赖关系

此时测试成功注入,因为当前没有bean,所有为null

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tst4D92q-1681790399058)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665499909164.png)]

(2)使用 @Primary微调基于注解的自动装配:

由于按类型自动装配可能会导致多个候选者(就如容器产生了三个宠物,但是我们只需要一个宠物),这时就可以用@primary注解,来优先考虑某个特定的bean。

我们给某个成员属性加上@primary注解,那么在容器根据自动装配时选择时会优先选择@primary的。 如果在候选bean中恰好存在一个主要的bean,那么它将成为自动连接的值。

例如:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PPpHBzTG-1681790399058)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665501076465.png)]

我们把其中一个设置为primary为true,那么就算容器有很多相同的bean,也会去优先找这个bean,其他的都是次要的bean。相当于做了次微调。

(3)@qualifier:

如果按照类型选择发现有很多相同bean,无法进行单一的选择,那么就按照名字来进行选bean注入:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6o7zLISS-1681790399058)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665501491782.png)]

常和@Autowired配合使用:表示自动装配时宠物选择了bean名字为dog的bean注入

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4c6U3zcJ-1681790399058)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665501512336.png)]

测试显示,选择了名字为dog的bean

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UdSLIn6D-1681790399058)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665501619656.png)]

(4)@Resource:

带有一个name属性,通过名字来找到合适的bean,如果没有显式指定名称,则默认名称为【字段名或setter方法的参数名】。 对于字段,它接受字段名。 对于setter方法,它采用bean属性名。

如:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZEgHOOKV-1681790399059)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665506171238.png)]

功能与上面的@qualifier相似。但是如果@Resource什么也不加:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YuLULcgl-1681790399059)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665506292771.png)]

那么它会默认name=“pet”,并去容器里找有没有叫pet的bean,如果是方法,就按照方法的属性名去寻找

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xpkP76RL-1681790399059)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665506393644.png)]

测试运行正确不报错,且宠物值为pet的bean,如果容器里没有叫pet的bean,那么就会报错。

如果@Resource什么也不加,且容器里只有一个宠物bean,那么默认就会去使用这个bean。

如:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k3hSVslU-1681790399059)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665506532589.png)]

xml:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lhNAlu69-1681790399059)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665506561016.png)]

所以@Resource的查找:

byName(可以传name值,也可不传,不传就按照属性的名字去查找),如果查找不到就按照byType去查找。

17 . 容器的启动过程(特别重要):

核心方法:refresh()

准备开蛋糕店的准备工作,选址,看看环境是否适合开蛋糕店

1、初始化Spring容器

prepareRefresh():准备刷新,spring对当前运行环境的一些检测,对日志的选择使用,一些环境相关的准备工作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s0fr6AiI-1681790399059)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665662957376.png)]

2 . 获得一个新的容器

这个阶段相当于租一个门面,同时准备好产品的制作流程

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C6fv9MUO-1681790399060)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665663084466.png)]

//忽略掉某些自动装配,如继承了ware接口后,会自动装配ware的相关东西(如BeanNameWare,自动装配bean的名字,根据相关实现方法看见需要一个beanName注入,而此时我们容器还没有设置完成,也没有存在我们bean找不到名字的情况,此时不应该自动装配,我们应该容器设置好后在考虑这种问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NN7CAsTY-1681790399060)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665667185298.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FX49pLKN-1681790399060)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665666922244.png)]

准备bean工厂:将要创建bean流程设置好

(蛋糕店要开业了,准备好做蛋糕的设备,人员,准备一些大酬宾的活动)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TOkE7H7N-1681790399060)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665663363396.png)]

如果有旧的容器,那么清空容器和容器中注册了的bean,创建新的容器DefaultListableBeanFactory。(族的店面以前就是商店,重新装修成蛋糕店)

try内的方法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OhbxX4S0-1681790399060)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665665763320.png)]

后置的处理beanFactory:

后置处理:(扩展点)

方法本身不执行任何操作,本身每部为空,而是有实现的子类去进行一些额外的操作,就是在每个生命周期节点留一个钩子,都可以让子类进行具体的独特的实现一些额外操作。

本身方法不处理,让对应的子类去处理(蛋糕店是加盟店,含有加盟的一些规则,但是我们的店面在规则之外可以做一些我们独有的对蛋糕店(beanFactory)的处理)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cSgXarq2-1681790399060)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665665790388.png)]

该方法需要有子类的实现和对方法的重写来进行后置处理,本身方法内部是空的,什么都没有,也就是当前的bean工厂不实现功能,让我们自己去添加一些对beanFactory额外的独有的扩展操作

后置处理器:依然是个扩展点)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PTh0JIXX-1681790399060)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665666116527.png)]

bean工厂大致准备好后该方法内部依然为空,只需要注入BeanFactoryPostProcessors让我们自己去添加对beanFactory额外的操作。

RegisterBeanPostProcessors:

工厂准备好后,工厂每创建一个bean,该方法都可以对每一个bean族谱一些额外处理(比如给这个bean做个标记(蛋糕店做好蛋糕给蛋糕做标签)),也是个扩展点,调用该方法后每次创建完bean都会传入这个bean,那么就可以对这个bean进行额外操作:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p6syI4rc-1681790399061)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665673681252.png)]

initMessageSource():对资源的一些处理(资源相关的)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4sNTbBs3-1681790399061)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665673749118.png)]

initplicationEventMulticaster():对事件的一些相关处理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d3HBIVfO-1681790399061)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665673809507.png)]

registerListeners():观察,监听相关

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eyjx0bm2-1681790399061)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665674192554.png)]

onRefresh():也是个扩展点,内部依然为空,留给子类去实现的,在该方法内部进行一些具体的实现。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bubBf27r-1681790399061)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665673926914.png)]

finishBeanFactoryInitialization(beanFactory);完成对bean工厂的初始化,加载配置文件初始化bean

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5hXHOgR3-1681790399062)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665676393649.png)]

finishRefresh():结束刷新,:也是个扩展点,内部依然为空,留给子类去实现的,在刷新结束时进行一些额外操作。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XJhgcMYL-1681790399062)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665676413581.png)]

3、bean工厂的准备阶段

相当于做一些基础装修,比如设备的采购

4、调用能调用的所有的BeanFactory后置处理器

这是留给我们进行扩展的,同时spring在也有很多的扩展实现。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Igyt3all-1681790399062)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665677565292.png)]

5、注册BeanPostProcessors

6、完成bean的创建

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-24nef5pN-1681790399062)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665677445938.png)]

18 . classpath扫描和组件管理(扫描类路劲和组件管理):

类路径扫描:扫描的注解

(1)@Component:管理组件的通用注解(类级注解)

组件就是一个bean,bean就是组件,一个bean由其他的组件组建而成的。

只要加了 @Component注解,就说明这个类将来生成一个bean,作为spring的一个组件,注入到容器里面。

如:只要该类加上这个注解,将来扫包(扫的是字节码文件,编译后的target下的路径)扫到就会默认等价于在xml配置中进行了元数据,bean的配置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dlh4dSMQ-1681790399062)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665821455726.png)]

除了@Component注解,还有:

@Repository、``@Service@Controller`是【@Component】用于更具体用例的注解(分别在持久性、服务和表示层中)。这些注解对于我们后期对特定bean进行批量处理时是有帮助的。这几个都是跟@Component差不多的功能,只不过是规定在那个范围使用。@Component注解一般是和本身业务无关的情况下使用。

1 . 使用配置文件开启扫描组件使注解生效:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kqZ9aPhq-1681790399062)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665822166503.png)]

开启扫描后,就会将使用了注解的类加载到容器中,创建出对应的bean

实例化测试:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WtPFXk6L-1681790399063)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665822418673.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dy4BhyiP-1681790399064)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665822385809.png)]

很明显拿到了这个bean。

2 . 使用配置类扫描组件使注解生效:

创建一个配置类:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Oi3Yjqvn-1681790399064)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665833269600.png)]

实例化测试:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WqAyZb3d-1681790399064)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665822782980.png)]

很显然第二种更方便

19 . bean命名。作用范围和过滤器:

(1)bean命名:

默认情况下,在注解的默认bean名字是类名的小写开头的:

它的默认bean命名:orderController

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-edAN62kc-1681790399064)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665827342625.png)]

在默认xml的bean命名情况下:

全限定类名+#0:

com.cgboy.controller.OrderController#0:代表第一个bean

com.cgboy.controller.OrderController#1:代表第二个bean

以此类推

(2)作用域的指定@Scope注解:

默认情况是单例的,(我们可以不写)如:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PMqf2o9V-1681790399064)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665827794808.png)]

设置为原型作用域:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TBKiWOBF-1681790399065)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665827960928.png)]

(3)使用过滤器自定义扫描:

在扫描包的情况下定义过滤器去扫描哪些类,哪些元数据,哪些不扫描

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X8GPYBm8-1681790399065)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665828670085.png)]

默认annotation”

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dqGcZNHu-1681790399065)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665829225717.png)]

assignable方式:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QfURBrMA-1681790399065)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665829323544.png)]

20 . @Bean的使用:

在组件内部,提供bean的元数据信息

已知User的内容:Address并有set方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HElc9DM8-1681790399065)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665831217520.png)]

对@Bean的使用方式:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xfuQCT52-1681790399066)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665831254038.png)]

21 . 基于java的容器配置:

(1)@Configuration:

带上这个注解的类表示这个类是配置相关的类

Spring新的java配置支持的中心组件是带注解的【@Configuration】类和带注解的【@Bean】方法(简单理解:@Configuration+@Bean可以组成一个配置类)

@Bean注解用于指示一个方法,该方法负责【实例化、配置和初始化】一个由Spring IoC容器管理的新对象。 对于那些熟悉Spring <beans/>XML配置的人来说,@Bean注解扮演着与<bean/> 元素相同的角色。 你可以在任何Spring @Component中使用@Bean注解方法。 但是,它们最常与@Configuration一起使用扮演一个。

@Configuration注解的一个类表明它的主要目的是作为beanDifination的源,我们通常称之为【配置类】。 此外,【@Configuration】类允许通过调用同一类中的其他【@Bean 】方法来【定义bean间的依赖关系】

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7SFE4sqN-1681790399066)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665833626663.png)]

(2)@Bean的其他知识:

方法级别的注解,与XML<bean/> 元素具有相同的能力。 注解支持<bean/>提供的一些属性,例如:

  • init-method
  • destroy-method
  • autowiring
  • name

你可以在带有【@Configuration】注解的类或带有【@Component】注解的类中使用【@Bean】注解。

有时需要为单个bean提供多个名称,或者称为bean别名。【@Bean】注解的’ name '属性为此接受String数组,如:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OtQ2pKbd-1681790399066)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665834747972.png)]

(3)@Configuration的其他知识:

一样是个类级别的注解

【@Configuration】是一个类级注解,指示一个对象是beanDifination的源。【@Configuration】类通过【@Bean】带注解的方法声明bean。 【在“@Configuration”类上调用“@Bean”方法也可以用来定义bean间的依赖关系】。

注入bean之间的依赖

@Bean方法在没有标注@Configuration的类中声明时,它们被认为是在【lite】模式下处理的。 在【@Component】中声明的Bean方法甚至在一个普通的类中声明的Bean方法都被认为是【lite】。在这样的场景中,【@Bean】方法是一种通用工厂方法机制。

@Configuration 不同,【lite】模式下 【@Bean】方法不能【声明bean】间的【依赖关系】。 因此,这样的【@Bean】方法不应该调用其他【@Bean】下的方法。 每个这样的方法实际上只是特定bean引用的工厂方法,没有任何特殊的运行时语义。

在一般情况下,@Bean方法要在【@Configuration】类中声明,这种功能情况下,会使用【full】模式,因此交叉方法引用会被重定向到容器的生命周期管理。 这可以防止通过常规Java调用意外调用相同的Bean,这有助于减少在【lite】模式下操作时难以跟踪的微妙错误。

@Bean@Configuration注解将在下面几节中深入讨论。 不过,我们首先介绍通过使用基于java的配置创建spring容器的各种方法。

当bean相互依赖时,表示这种依赖就像让一个bean方法调用另一个bean方法一样简单,如下面的示例所示:

@Configuration
public class AppConfig {

    @Bean
    public BeanOne beanOne() {
        // full模式(单例)可以直接调用方法,这个调用过程由容器管理,lite模式(原生)这就是普通方法调用,多次调用会产生多个实例。
        return new BeanOne(beanTwo());
    }

    @Bean
    public BeanTwo beanTwo() {
        return new BeanTwo();
    }
}

在前面的例子中,【beanOne】通过构造函数注入接收对【beanTwo】的引用。

考虑下面的例子,它显示了一个带注解的@Bean方法被调用两次:

@Configuration
public class AppConfig {

    @Bean
    public ClientService clientService1() {
        ClientServiceImpl clientService = new ClientServiceImpl();
        clientService.setClientDao(clientDao());
        return clientService;
    }

    @Bean
    public ClientService clientService2() {
        ClientServiceImpl clientService = new ClientServiceImpl();
        clientService.setClientDao(clientDao());
        return clientService;
    }

    @Bean
    public ClientDao clientDao() {
        return new ClientDaoImpl();
    }
}

clientDao() 在【clientService1()】和【clientService2()】中分别被调用一次。 由于该方法创建了一个新的【ClientDaoImpl】实例并返回它,所以通常期望有两个实例(每个服务一个)。 这肯定会有问题。在Spring中,实例化的bean默认有一个【单例】作用域,在调用父方法并创建新实例之前,首先检查容器中是否有缓存的(有作用域的)bean。

22 . 如何将一个数据源注入到容器内:

(1)使用xml配置的方式:

引入依赖:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y5Jjv96u-1681790399066)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665841007695.png)]

xml文件配置:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YeaeuJ41-1681790399066)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665841158344.png)]

(2)使用注解的方式:

我们引入依赖后,创建一个配置类即可:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KumwJ9Eh-1681790399066)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665841441569.png)]

常用的比较重要的注解:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZjYUK57N-1681790399067)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665841511510.png)]

23 . @import:

(1)使用配置文件的引入方式:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jmS6cAam-1681790399067)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665846959444.png)]

如上图,这样子就引入了ioc.xml的配置到了ware.xml上,实现了模块化,这样的话同一类型的bean放在同一个配置文件上,不至于其他的配置文件都要添加该类型的bean,只要引入就可以了(类似继承)

(2)使用@import的方式:

要使用注解引入的前提必须是@Configuration包装的配置类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iyXjrTpD-1681790399067)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665847318828.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0ulmhaEe-1681790399067)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665847545568.png)]

注解引入操作:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YpAIOh2T-1681790399067)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665847444308.png)]

这样AppConfig引入了这两个类的配置

24 . 结合Java和XML配置

Spring的【@Configuration】类支持的目标并不是100%完全替代Spring XML,有些场景xml仍然是配置容器的理想方式。

我们有如下选择:

1、容器实例化在一个“以XML为中心”的方式使用,例如,“ClassPathXmlApplicationContext”。

2、"以java编程的方式为中心”的方式,实例化它通过使用【@ImportResource】注解导入XML。

以xml为中心使用“@Configuration”类

最好从XML引导Spring容器,并以一种特别的方式包含【@Configuration 】类。将【@Configuration 】类声明为普通的Spring <bean/> 元素。记住,【@Configuration】类最终是容器中的beanDifination。

下面的例子展示了Java中一个普通的配置类:

@Configuration
public class AppConfig {

    @Autowired
    private DataSource dataSource;

    @Bean
    public AccountRepository accountRepository() {
        return new JdbcAccountRepository(dataSource);
    }

    @Bean
    public TransferService transferService() {
        return new TransferService(accountRepository());
    }
}

下面的例子显示了一个’ system-test-config.xml '文件的一部分:

<beans>
    <!-- enable processing of annotations such as @Autowired and @Configuration -->
    <context:annotation-config/>
    <context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>

    <bean class="com.acme.AppConfig"/>

    <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
</beans>

下面的示例显示了一个可能的’ jdbc '。 属性的文件:

user=root
password=root
url=jdbc:mysql://127.0.0.1:3306/ydlclass?characterEncoding=utf8&serverTimezone=Asia/Shanghai
driverName=com.mysql.cj.jdbc.Driver
public static void main(String[] args) {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/com/acme/system-test-config.xml");
    TransferService transferService = ctx.getBean(TransferService.class);
    // ...
}

因为【@Configuration】是用【@Component】注解的,所以被【@Configuration】注解的类会自动被组件扫描。 使用与前面示例中描述的相同的场景,我们可以重新定义system-test-config.xml来利用组件扫描。

下面的示例显示了修改后的system-test-config.xml文件:

<beans>
    <!-- picks up and registers AppConfig as a bean definition -->
    <context:component-scan base-package="com.acme"/>
    <context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>

    <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
</beans>

使用@ImportResource以类为中心使用XML

在【@Configuration】类是配置容器的主要机制的应用程序中,可能仍然需要使用至少一些XML。 在这些场景中,您可以使用【@ImportResource】注解,并只定义所需的XML。 这样做可以实现一种“以java为中心”的方法来配置容器,并将XML最小化。

下面的例子说明了这一点:

@Configuration
@ImportResource("classpath:/com/acme/properties-config.xml")
public class AppConfig {

    @Value("${jdbc.url}")
    private String url;

    @Value("${jdbc.username}")
    private String username;

    @Value("${jdbc.password}")
    private String password;

    @Bean
    public DataSource dataSource() {
        return new DriverManagerDataSource(url, username, password);
    }
}

properties-config.xml

<beans>
    <context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>
</beans>

jdbc.properties:

jdbc.url=jdbc:hsqldb:hsql://localhost/xdb
jdbc.username=sa
jdbc.password=

启动容器:

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
    TransferService transferService = ctx.getBean(TransferService.class);
    // ...
}

25 . BeanFactory和FactoryBean的区别(重点常问):

BeanFactory是一个接口,它是Spring中工厂的顶层规范,是SpringIoc容器的核心接口,它定义了getBean()containsBean()等管理Bean的通用方法。

BeanFactory:bean工厂,使用BeanFactory管理我们的bean,从容器当中获取检索我们需要的bean

FactoryBean:给我们的工厂提供bean,它是一个能生产或修饰对象生成的工厂Bean。用它来创建复杂对象(如:不知道类名,用全限定类名使用反射forName)它能在需要的时候生产一个对象,且不仅仅限于它自身,它能返回任何Bean的实例

FactoryBean提供的三种方法:

FactoryBean获取bean并交给spring工厂去管理(核心)

获取bean的类型(核心)

判断是否是单例的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N4BVQ5aC-1681790399067)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665929343713.png)]

FactoryBean获取bean并交给spring工厂去管理(进行复杂对象的创建,使用反射来进行创建bean),获取bean的类型,判断是否是单例的

26 . 环境抽象:(Environment接口)

接口是一个抽象,集成在容器中,它模拟了应用程序环境的两个关键方面:【profiles】 and 【properties】。

(1)@Profile:

选定你要用的环境:

已知我们设置了两个数据源dev和prod:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1Ch4t5xw-1681790399068)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665991382372.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HPVZDVFL-1681790399068)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665991443819.png)]

ioc.xml配置对应数据源环境:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nxXLHhbZ-1681790399068)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665991537277.png)]

建立一个配置类:指定了两个产生的bean注入到对应的@Profile指定的环境

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3nIXDHhi-1681790399068)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665991472191.png)]

测试:可以看出指定了dev的环境,所以拿到的是devDatatSource的bean

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CHmr0Vyo-1681790399068)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665991578959.png)]

(2)@PropertySource,@Value:

使用该注解可以直接把目标的配置文件引入,加载到环境中使用:

已知配置文件:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ENTvTj5b-1681790399068)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1665995457354.png)]

如:classpath:config.properties(从类路劲下找到config配置文件加载到该环境)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MqgGhGU4-1681790399069)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666009582240.png)]

测试:显示出xml中的内容

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ikusLdnp-1681790399069)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666009630739.png)]

27 . 事件监听注解:@EventListener:

在测试时,使用了ApplicationContext触发了事件的发动,该注解监听到执行了该方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9mJU241A-1681790399069)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666346485607.png)]

这个方法加上该注解就作为观察者,将来只要监听到事件后,就会调用该方法的内容。

容器与 bean之间的关系案例:使用JdbcTemplate:

Spring框架对JDBC进行封装,使用JdbcTemplate方便实现对数据库操作

引入mysql依赖:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ccGfAisX-1681790399069)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666069889834.png)]

指定mysql数据库中ssm数据库,用户密码等,这里不用设置Driver,因为会自动引入去寻找:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-13xegEDQ-1681790399069)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666069722384.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P7FvnAYQ-1681790399070)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666069743562.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EG4VpwV0-1681790399070)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666069755356.png)]

User相关getset等已设置:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ggJZUyGA-1681790399070)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666069777394.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H5vex5nG-1681790399070)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666069816543.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FnvxYwRm-1681790399070)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666069825633.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nmd9WUdv-1681790399071)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666069864982.png)]

第三章 spring对资源的操作

1 . Resource接口:

创建一个ResourceTest类和jdbc.properties文件(暂无内容):

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fhu20oDE-1681790399071)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666072585116.png)]

很明显能拿到该文件的资源。

拿到文件系统的目标文件资源:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L1sYEdBH-1681790399071)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666072656320.png)]

这样也能拿到:去也是系统文件去找的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HgMnlA1b-1681790399071)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666073143036.png)]

也可使用calsspath强制去类路径classpath当前路径下去加载文件:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8FkakETl-1681790399071)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666073216628.png)]

多种使用情况:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PO1NzsNk-1681790399072)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666073816078.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GtaAlWxy-1681790399072)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666074588710.png)]

第四章 验证(Validation)、数据绑定(Data Binding)和类型转换(Type Conversion)

1 . BeanWrapper:(只是个工具)

bean工厂在初始化一个bean后,都会将其包装成一个beanwrapper,因为beanwrapper只是个工具,这样就可以调用更多方法很轻松的完成一些如设置和获取属性值,获取属性描述符已确定他们是否可读可写…等的复杂操作。【BeanWrapper】提供了对嵌套属性的支持,允许对子属性进行无限深度的检索。 说的简单一点,就是这个类能帮助我对使用更简单的api通过反射操作一个bean的属性。(内部底层原理都是反射来操作的)

创建公司类和员工类:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0GDAiEws-1681790399072)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666075651097.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-46w8uxaq-1681790399072)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666075660820.png)]

测试:由此可见包装了BeanWrapper后对属性的操作要直接使用反射来进行属性的操作方便多了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vbgBgsz0-1681790399072)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666076028093.png)]

对资源的检索功能:也比反射方便

在以上代码基础上:检索公司bean的的name属性

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zq6Qp3dU-1681790399072)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666076342732.png)]

2 . PropertyEditor编辑器:

Spring使用【PropertyEditor】的概念来实现【对象】和【字符串】之间的转换。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pKxhzt5O-1681790399073)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666076948975.png)]

上述xm的user,比如对它的age赋值时,我们知道了类中为int类型,在value写上

12,但时xml中spring会判断它是否是数字还是string类型,通常我们自己是使用Integer来解决,自然soring也是如此不过做了很多统一的规范,其实在xml中都是字符串的形式,spring就是用 PropertyEditor编辑器来进行这些操作将其转换为对应的类型。

3 . 类型转换Convertor:

Converter的API:

实现类型转换逻辑很简单,如下面的接口定义所示:

package org.springframework.core.convert.converter;

public interface Converter<S, T> {

    T convert(S source);
}

创建你自己的转换器,需要实现【转换器】接口,并使用泛型“S”作为你要转换的【原始类型】,“T”作为你要转换的【目标类型】。

4 . DataBinder数据验证:

继承该接口实现核心方法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KTzFoCry-1681790399073)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666090094449.png)]

测试:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fZ2fMq6X-1681790399073)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666090107785.png)]

第五章 spring表达式语言(SpEL)(重要,用时查文档):

1 . 初步操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9mBmoXso-1681790399073)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666091024815.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uePQXwNL-1681790399073)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666091147926.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SimLkgmS-1681790399073)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666091990081.png)]

2 . 在xml中使用表达式:

对对象属性赋值:

T(目标对应类).调用对应类方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R40wfKzy-1681790399074)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666092258328.png)]

3 . 在注解上使用:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UHxRAxwz-1681790399074)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666092684243.png)]

测试:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2O9C76Qh-1681790399074)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666092711576.png)]

第六章 spring面向切面编程(aop)(重点)

1 . aop概述:

简单模拟:

创建好类并实现对应接口的方法:

UserService:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yCtNtP6W-1681790399074)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666435850372.png)]

OrderService:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hvaiWDcI-1681790399074)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666435884411.png)]

对应配置类:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AH6QuK2O-1681790399075)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666435933565.png)]

创建以下类继承BeanPostProcessor:实现动态代理,在创建bean调用用register方法执行方法内容前执行开始事务,执行方法内容后,在添加入了提交事务的操作,总的就是对目标bean执行相应方法时,对这个方法进行了增强效果。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RLrtKRJJ-1681790399075)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666435953198.png)]

测试:通过以下代码,,调用方式发现对方法进行了增强,我们通过拿到目标类继承的接口来获取到bean,通过动态代理来对方法的操作,这样极大的降低了耦合的关系。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-agQqovRG-1681790399076)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666436186746.png)]

相关术语

Aspect(切面):

把我们的关注点形成一个模块,该关注点可能会被切成很多哥对象,交给容器。容器会做出对应的操作。(就比如上面对userservice的方法register()作为一个关注点做成一个切面,为后续对方法进行增强做准备)

Join Point(连接点)

在程序中一个方法,方法执行内容前和方法执行完内容后,能把增强内容出入进去的都是一个连接点。

如图:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YIZUJf0z-1681790399076)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666510345569.png)]

Advice(通知)

在连接点新加入一些内容(新增代码)。就是连接点内增强的内容。

Pointcut(切入点)

有一个切入点表达式,通过该表达式我们可知道通知可以放到哪些连接点上。

introduction(引入):(用的不多)

spring允许引入新的接口 (同时要又特定的实现)到任何的被代理的对象。实现其他的接口同实现接口的方法。

Target object(目标对象)

被通知对象(就是原始对象bean),如图:对容器的这个bean操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ur2gbsJl-1681790399076)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666510772293.png)]

Aop proxy(Aop代理)

在Spring中,AOP代理可以是JDK动态代理(通过实现接口)或者CGLIB代理(通过静态类)。

Weaving(织入)

把切面(aspect)连接到其它的应用程序类型或者对象上,并创建一个被通知(advised)的对象,这个过程叫织入。(将对应通知植入到目标对象形成一个代理对象,就是把通知放在连接点的过程)。

Spring AOP包括以下类型的通知:

  • Before advice : 方法内容运行前的通知,前置通知

  • After returning advice : return之后执行的通知

  • After throwing advice:在方法通过抛出异常退出时运行的通知。

  • After (finally) advice: 方法内容都运行完后执行的通知

  • Around advice:环绕通知(可实现上面所有通知),方法的内容前有都会有增强内容

    注意: 能用前置通知就用前置通知,不行采用后置通知,实在没办法采用围绕通知。

首先引入依赖:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XOhBhuEQ-1681790399077)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666511756987.png)]

定义一个切面:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3LCtWmSt-1681790399077)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666349760478.png)]

声明一个切入点:用“@Aspect”标注的类可以有方法和字段,与任何其他类一样。 它们还可以包含切入点、通知和引入(类型间)声明。

【切入点确定感兴趣的连接点】,从而使我们能够控制通知何时运行。

2 . 切入点匹配规则:

(1)无@:

execution:红线部分为切入点,向下方的方法为连接点,方法执行内容前和方法执行完内容后,都是一个连接点。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-88kKNtBh-1681790399077)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666411955144.png)]

在各种格式情况下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZRVqNmck-1681790399078)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666368138212.png)]

  • within`: 用于匹配指定类型内的方法执行。(匹配整个类都感兴趣)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5tHfSUUx-1681790404163)(null)]

  • this: 用于匹配当前【AOP代理对象】类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能【包括引入接口】也进行类型匹配。(配置整个类)

    引入:使其代理对象可能实现更多接口

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vq8cZmgD-1681790404261)(null)]

  • target: 用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就【不包括引入接口】也进行类型匹配。(配置整个类)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6P8bumaO-1681790404316)(null)]

  • args: 限制匹配连接点(使用Spring AOP时的方法执行),其中参数是给定类型的实例。 (参数类型匹配)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HNQHhHkw-1681790400885)(null)]

bean: 使用“bean(Bean id或名字通配符)”匹配特定名称的Bean对象的执行方法;Spring ASP扩展的,在AspectJ中无相应概念。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LjwabwQv-1681790404405)(null)]

(2)有@:

  • @target`: 用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解 。(类上的注解)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8FXlkAoM-1681790404457)(null)]

如:MyAspect类上又A注解,那么切点内只要有A注解的它都感兴趣

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jpW4RNww-1681790399080)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666368548022.png)]

  • @args`: 用于匹配当前执行的方法传入的参数持有指定注解的执行。(参数上的注解)

    如:参数上有注解切点就对它感兴趣:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k25ZQZuN-1681790399080)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666368918757.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2dQMncNg-1681790404568)(null)]

  • @within: 用于匹配所有持有指定注解类型内的方法。(类上的注解)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ff0PR3rD-1681790404620)(null)]

  • @annotation: (常用)于匹配当前执行方法持有指定注解的方法。(方法上的注解)

    如:方法上有A这个注解那么切入点就对它感兴趣

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VkN9eaqh-1681790399081)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666368831462.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3UnV8eqB-1681790399081)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666368678157.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jRnAUCYC-1681790404739)(null)]

3 . 切入点表达式:

可以使用’ &&’ || ‘和’ ! '组合切入点表达式。 您还可以通过名称引用切入点表达式。 下面的例子展示了三个切入点表达式:

//所有公开的都匹配
@Pointcut("execution(public * *(..))")
private void anyPublicOperation() {} 

//该包及其子包都匹配
@Pointcut("within(com.xyz.myapp.trading..*)")
private void inTrading() {} 

//将上面俩哥的匹配都纳入自己的匹配范围:
@Pointcut("anyPublicOperation() && inTrading()")
private void tradingOperation() {} 

3 . 声明通知:

已知对应类接口:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OFeClDhY-1681790399082)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666451058975.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rRWecHvu-1681790399082)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666514393366.png)]

配置类:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VsoxCjcd-1681790399082)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666451286517.png)]

切面:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F8s4JLwv-1681790399082)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666514126073.png)]

测试:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VqrEWJI6-1681790399083)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666451986491.png)]

输出结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cJcF1teg-1681790399083)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666514283372.png)]

在userservice和orderservice的方法运行前都执行了前后i通知的内容,随后运行方法的内容,已知orderservice的方法内有返回值,所以在return执行后执行了@Afterreturning通知的内容,随后方法执行完毕后执行后置通知,由于没有发生异常所以没有执行异常通知的内容,最后执行了环绕通知

(1)通知的参数:

Spring提供了完整类型的通知,这意味着您可以在【通知签名】中声明【所需的参数】(就像我们前面在返回和抛出示例中看到的那样)。

  • getArgs(): 返回方法参数。

  • getThis(): 返回代理对象。

  • getTarget(): 返回目标对象。

  • getSignature(): 返回被通知的方法的签名。

  • toString(): 打印被建议的方法的有用描述。

    如下:传入方法参数,调用目标对象的方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3MdtCI96-1681790399083)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666515778152.png)]

测试结果:有结果可知,因为在目标方法运行前执行前置通知,该通知内部执行该方法一次。随后执行前置通知的内容,之后执行方法内容…

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NcmNC2Wr-1681790399084)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666515980788.png)]

在args表达式中使用【参数名】代替类型名,则在【调用通知】时将传递相应值作为参数值,如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2LWWpBnI-1681790399084)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666516723397.png)]

4 . 引入介绍(用的不多):

对应接口和实现类:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xDLJdXD8-1681790399084)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666517857262.png)]

主配置:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ACXP0yhH-1681790399084)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666517964171.png)]

OrderService引入Activity:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UDoafFFp-1681790399084)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666517913209.png)]

测试:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c58nMVIM-1681790399085)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666517940405.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JdIfvVXG-1681790399085)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666517630074.png)]

5 . aop基于xml配置

小知识:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xma2UYe5-1681790399085)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666525104142.png)]

我们不适用注解,通过xml配置手动进行代理:

创建aop.xml文件:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AK4OXCCm-1681790399085)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666527123519.png)]

对应的目标类和接口:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6Da0X534-1681790399085)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666532524865.png)]

xml对应的切面类:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VzIMF8Nh-1681790399086)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666527276866.png)]

测试:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pmH3vK12-1681790399086)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666527818762.png)]

添加环绕通知:

xml配置:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gMGSeBsR-1681790399086)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666528697542.png)]

对应切面类:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DIBH5Eew-1681790399086)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666528757352.png)]

测试:可以看出环绕通知,在方法执行前后都行了增强。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IZH7fxwu-1681790399086)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666528784900.png)]

引用的xml设置:

types-matching:目标路径下的类实现下面路径下的接口,默认实现哪个接口实现类的实现方法。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9RaQZNQ2-1681790399086)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666529091449.png)]

6 . aop:advisor的使用:(前置通知)

对应的类:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KQCfxkcH-1681790399087)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666532517233.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yPmZEiFL-1681790399087)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666532340351.png)]

xml配置:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DslC01JI-1681790399087)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666532384656.png)]

测试:从结果得出,在bean调用方法前执行了通知的内容,实现了增强

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OiloxGl5-1681790399087)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666532581398.png)]

第七章 事务管理

1 . 理解Spring框架的事务抽象:

spring事务对事务抽象体现在一下三个类中:PlatformTransactionManagerTransactionDefinitionTransactionStatus

(1)TransactionManger(事务管理器)

所有的事务统一抽象出来,由TransactionManger来管理。

TransactionManager主要有一下两个子接口:

**org.springframework.transaction.PlatformTransactionManager接口用于:为不同平台(如mybatis,jdbc等)提供统一抽象的事务管理器,重要。**将来不同平台要使用它就要为它实现相对应的接口,具体的实现由具体的平台独立完成。(就三个方法,拿到事务,提交和回滚)

org.springframework.transaction.ReactiveTransactionManager接口用于响应式事务管理,这个不重要。

(2)TransactionDefinition (事务的定义)

该接口主要功能是提供一些事务的配置。

Propagation(传播行为):比如一个s1的事务执行时执行到某个步骤时发现需要s2的事务执行,此时去执行s2的事务,s2事务也是个独立的事务,所以要s2执行完后才能继续去执行s1事务,这两者就发生了嵌套。那么s2的事务就被传播到了s1事务当中,这其中也需要一些配置来执行。

Isolation:(隔离级别)该事务与其他事务的工作隔离的成都。

Timeout:(超时时间)这个事务在执行了多长时间内还没由执行成功,那么直接归滚。

只读状态:当前事务下,只允许读操作。

小知识:接口里面定义的变量都是静态变量。

(3)TransactionStatus:(事务的状态)

该接口为事务代码提供了一种简单的方法来控制事务执行和查询事务状态。

2 . 编程式事务管理

Spring Framework提供了两种编程式事务管理的方法:

TransactionTemplate和TransactionManager

(1)使用TransactionManager:

使用PlatformTransactionManager:

对应接口和实现类:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qegk3CIh-1681790399087)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666596943759.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hHuYVTz2-1681790399087)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666596962541.png)]

引入jdbcTemplate和事务相关依赖:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qwrrTIkh-1681790399088)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666597075981.png)]

jdbc.properties文件:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xbaGv88y-1681790399088)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666597168825.png)]

xml配置:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zFV78RX1-1681790399088)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666597205759.png)]

<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <!--把jdbc.properties引入进来-->
    <context:property-placeholder location="jdbc.properties"/>
    <!--给定扫包范围-->
    <context:component-scan base-package="com.cgboy"/>

    <!--注入事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--配数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${url}"/>
        <property name="driverClassName" value="${driverName}"/>
        <property name="username" value="${user}"/>
        <property name="password" value="${password}"/>
    </bean>

    <!--注入jdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>

</beans>

测试:转账给jerry300(已知数据库中tom1000快,jerry2000快)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ElgbDgXe-1681790399088)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666597331024.png)]

输出结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P16RB3ms-1681790399088)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666597471397.png)]

数据库显示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1UnXJMDI-1681790399089)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666597521327.png)]

可这依然存在问题:

比如在转账的业务逻辑中,加入报错的异常:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TyJOgez2-1681790399089)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666599873086.png)]

那么就会造成在tom给jierry转账扣钱后,产生异常,后面的不运行,而jerry的收钱的逻辑并没有执行,导致tom的钱扣了,jerry没有收到的问题,所以我们需要事务来解决这种情况:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I5BaFnS5-1681790399089)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666600391749.png)]

(2)使用TransactionTemplate:

xml配置:引入TransactionTemplate的bean并使用事务管理器来进行操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iWIWXgoW-1681790399089)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666601229611.png)]

其他的配置跟上面的差不多,修改业务:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NWJ5D9Ur-1681790399089)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666601902644.png)]

测试:在不发生异常时,数据库的数据成功修改,发生异常后事务回滚没有被修改。更简洁。

3 .使用aop 进行扩展 :

如上的业务,当有许多业务时,我们每次都要写上业务的事务的提交,回滚的重复代码,十分的繁琐,所以我们可以结合使用aop的环绕通知,在每次执行业务时就可自动地加上有关事务的操作,会显得十分的方便。

引入依赖:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C6IHRE1n-1681790399089)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666614939772.png)]

jdbc配置:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vPmp4lDV-1681790399089)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666621643973.png)]

xml配置:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P72qrgMR-1681790399090)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666615007316.png)]

通知bean传入切点,与该路径下的方法进行匹配,随后获取到bean对象调用方法时通过代理方法在执行方法内容时会执行环绕通知的内容。

创建一个TxAdvice类:

  • getArgs(): 返回方法参数。
  • getThis(): 返回代理对象。
  • getTarget(): 返回目标对象。
  • getSignature(): 返回被通知的方法的签名。
  • toString(): 打印被建议的方法的有用描述。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t67u8cUc-1681790399090)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666614882139.png)]

AccountService类中被代理方法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VF1JEnWX-1681790399090)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666622176381.png)]

测试:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RIYQD8Kl-1681790399090)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666621666272.png)]

我们多次操作数据库的业务时,都会自动的给它加上事务,这样当我们的业务出现异常时不需要我们自己去写很多次了,环绕通知就会帮我们完成。有上述代码,我们有1/0的异常,通过拿到bean代理方法会自动给我们不上异常信息:并将事务回滚

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tz8oXmrD-1681790399090)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666623620101.png)]

此时数据库中的数据也是没有被修改的。当我们将int i=1/0删掉运行时,运行正常,且数据库中的数据被修改。

4 . 声明式事务:

aop扩展其实就是手写的一个声明事务。

xml配置声明事务的相关配置:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cKNN4gxp-1681790399090)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666626294536.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6sIXXIlE-1681790399091)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666627167788.png)]

被代理方法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FHg9yU5e-1681790399091)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666626976234.png)]

测试时的结果与上面aop扩展的一样。

5 . 事务回滚(非常重要)

默认情况配置中,spring只针对运行时异常(RuntimeException)进行回滚。报错(Error)也会回滚。但是当我们抛出检查性异常不会造成回滚(会爆出检查性异常错,但是事务不会回滚)。

注意:如果我们将运行时异常trycatch操作,那么就意味着我们在程序执行时捕获到异常并处理了异常,那么导致spring会感知不到这个异常了,那么后台虽然出现报了异常错,但是事务并没有进行回滚。如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cYoHcpXl-1681790399091)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666670664675.png)]

运行时业务确实打印了异常报了错,我们打开数据库时发现数据却被修改了,说明事务没有回滚。

我们可以准确的配置哪些Exception类型将事务标记为回滚。

如下:在以get开头的只读中,方法中出现NoProductInStockException机器子类异常进行回滚

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nfTGIMAg-1681790399091)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666670001333.png)]

指定updateStock方法不回滚的异常:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KzwulUce-1681790399091)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666670158101.png)]

当Spring Framework的事务,捕获异常并参考配置的回滚规则来决定是否将事务标记为回滚时,最强匹配规则(越靠近子类匹配性越强)胜出。 因此,在以下配置的情况下,除了InstrumentNotFoundException之外的任何异常都会导致事务的回滚:

<tx:advice id="txAdvice">
    <tx:attributes>
    <tx:method name="*" rollback-for="Throwable" no-rollback-for="InstrumentNotFoundException"/>
    </tx:attributes>
</tx:advice>

6 . 事务的配置:

<tx:advice/> 设置

本节总结了通过使用<tx:advice/> 标记可以指定的各种事务设置。 默认的<tx:advice/> 设置是:

  • 传播行为是REQUIRED.
  • 隔离级别为 DEFAULT.
  • 事务处于可读写状态。
  • 事务超时默认为底层事务系统的默认超时,如果不支持超时,则为none。
  • 任何RuntimeException触发回滚,而任何选中的Exception不会。

您可以更改这些默认设置。 下表总结了嵌套在<tx:advice/><tx:attributes/>标签中的<tx:method/>标签的各种属性:

属性Required?默认值描述
nameYes要与事务属性相关联的方法名。 通配符()字符可用于将相同的事务属性设置与许多方法相关联(例如,’ get ‘、’ handle* ‘、’ on*Event '等等)。
propagationNoREQUIRED事务传播行为。
isolationNoDEFAULT事务隔离级别。 仅适用于’ REQUIRED ‘或’ REQUIRES_NEW '的传播设置。
timeoutNo-1事务超时(秒)。 仅适用于传播’ REQUIRED ‘或’ REQUIRES_NEW '。
read-onlyNofalse读写事务与只读事务。 只适用于’ REQUIRED ‘或’ REQUIRES_NEW '。
rollback-forNo触发回滚的“Exception”实例的逗号分隔列表。 例如,“com.foo.MyBusinessException, ServletException”。
no-rollback-forNo不触发回滚的“Exception”实例的逗号分隔列表。 例如,“com.foo.MyBusinessException, ServletException”。

如:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UOBP0EuO-1681790399092)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666672251242.png)]

7 . 使用@Transactional(用的相当多):

只要将该注解放到类上或方法上,就能起到声明事务语义的作用。将该注解写道类上,那么该类和它的子类都会赋予该事务的语义。但是子类从父类继成来的方法

没有被赋予事务。

如:继承了A的B,B继承的A的方法是没有赋予事务的,如果要让B继承的方法也赋予事务的语义,可在方法上加上@Transactional。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aiauZErs-1681790399093)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666673087939.png)]

当然光靠一个@Transactional注解救恩那个完成事务的配置是远远不够的,我们后续会解释。

8 . 纯注解实现事务的配置:(重要)

相关依赖:

<?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>comcgboy</groupId>
    <artifactId>spring</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>soring-jdbcTemplate</module>
        <module>spring-aop</module>
        <module>spring-transactionmanager</module>
    </modules>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>

        <!--spring核心组件-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.2.18.RELEASE</version>
        </dependency>
        <!-- SpringIoC(依赖注入)的基础实现 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.2.18.RELEASE</version>
        </dependency>
        <!--Spring提供在基础IoC功能上的扩展服务,此外还提供许多企业级服务的支持,
        如邮件服务、任务调度、JNDI定位、EJB集成、远程访问、缓存以及各种视图层框架的封装等 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.18.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.2.18.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.18.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>javax.annotation</groupId>
            <artifactId>javax.annotation-api</artifactId>
            <version>1.3.2</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.9.1</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.2</version>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.6</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.30</version>
        </dependency>
    </dependencies>



    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>9</source>
                    <target>9</target>
                    <encoding>utf-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

jdbc配置文件:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SmWAvPia-1681790399093)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666677558999.png)]

主配置类:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xVxbqRgK-1681790399093)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666677515538.png)]

相关类和接口:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Eg77jgds-1681790399093)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666677647931.png)]

测试:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YKuE05W8-1681790399094)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666677682189.png)]

运行后哦查看数据原来tom1000快变700,jerry2000块变成2300。说明程序运行后,提交了事务,而如果我们加入:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-izXN0LEV-1681790399094)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666677797848.png)]

,数据库查看数据没有被改变,说明事务被回滚了。由此可见我们的业务都被添加上了事务。

9 . 事务的传播行为(重要):

增删改 需要事务

查询 不需要事务

以下两个最常用

REQUIRED:(适合纯修改类方法)

一个大的事务是由很多小的事务构成的(事务嵌套)。事务嵌套成功后,当前事务(大事务)有事务执行时,就在当前事务中来执行。如果没有,新建一个事务,自己写的内容运行在这个事务当中。

例如一个大业务有增删改那么久一定要添加事务,这个大业务内部还有小业务且也有增删改操作,本来这个小业务也要添加事务,但是可以把这个小业务的事务糅合在大业务的事务内,也就是小业务不加事务,统一用大业务的事务来执行。如果小业务没有事务也是统一和大事务一起操作的。

SUPPORTS:(适合纯查询类方法)

表示当前方法不需要事务上下文,如果存在当前事务的话,那么方法就在这个事务中执行,否则以无事务的方式运行。

例如当这个大业务只是查询操作,那么就不需要添加事务,而小业务中也没有事务,那么就不需要添加事务,但是小业务有事务时,那么就按照小事务执行。

剩下的都不很常用:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DHsuIiSy-1681790399094)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666683494252.png)]

传播行为演示:

数据库对应表:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BHlzB6Gf-1681790399094)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666686270523.png)]

对应接口和实现类:

其中该方法(小业务)传播行为为REQUIRED

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h4ijeBuI-1681790399094)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666686000070.png)]

大的业务中嵌套了小业务的事务,且传播行为为REQUIRED

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MI2BMZWR-1681790399095)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666686104841.png)]

测试:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y8znrPeO-1681790399095)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666686322203.png)]

因为大业务中有事务,小业务中也有事务,所以统一按照大事务来执行,在运行时

大事务出现异常报错,账户,日志事务回滚,数据不会改变。

若假设大业务没有事务,小业务有事务:我们把大业务事务取消掉(把@Transactional注掉)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sR8CZLAh-1681790399095)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666687644933.png)]

小事务中发生错误造成回滚,数据库中日志表不会改变,大业务中没有事务也不会改变。由此可见这里时小事务自己新建事务来完成的。如果小事务没有异常,则会对日志表提交大日志数据。大业务中没有事务也不会改变。

第八章 Mybatis-Spring 框架整合

更多详细的内容请上官网:mybatis-spring

Mybatis-Spring 框架会帮我们将Mybatis的代码无缝整合到Spring的中。

它将允许 MyBatis 参与到 Spring 的事务管理之中,创建映射器 mapper 和 SqlSession 并注入到 bean 中,以及将 Mybatis 的异常转换为 Spring 的 DataAccessException。 最终,可以做到应用代码不依赖于 MyBatis,Spring 或 MyBatis-Spring。

引入依赖:

<?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>com.cgboy</groupId>
    <artifactId>ssm</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>
    <!-- 单元测试 -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope>
    </dependency>

    <!-- spring上下文的依赖 包含了aop,bean和core-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.23</version>
    </dependency>
    <!-- springjdbc相关的依赖 包含了jdbcTemplate以及事务-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.3.23</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.9.1</version>
    </dependency>

    <!-- 数据源-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.2.13</version>
    </dependency>
    <!-- 日志 -->
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.4.1</version>
    </dependency>
    <!-- 数据区驱动-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.30</version>
    </dependency>

    <!-- mybatis-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.11</version>
    </dependency>

    <!-- 整合spring和mybatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.6</version>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.24</version>
    </dependency>
</dependencies>



    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>9</source>
                    <target>9</target>
                    <encoding>utf-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

jdbc.properties文件配置:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jYqohhBv-1681790399095)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666700551007.png)]

application.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:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mybatis="http://mybatis.org/schema/mybatis-spring"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd
        http://mybatis.org/schema/mybatis-spring
        http://mybatis.org/schema/mybatis-spring.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">


    <!--把jdbc.properties引入进来-->
    <context:property-placeholder location="jdbc.properties"/>
    <!--给定扫包范围-->
    <context:component-scan base-package="com.cgboy"/>

    <!--扫描该路径下的mapper文件(发现映射器)-->
    <mybatis:scan base-package="com.ydlclass.mapper"/>

    <!-- 整个整合就是在围绕sqlSessionFactory -->
    <!--从这个sqlsessionfactory工厂拿到sqlsession会话的bean,通过sqlsessionbean去读
        mybatis的配置文件
         根据读取的内容执行了对数据库的操作。
        注意:
        只需要一个sqlSession的bean,当其他的mapper需要用时将其注入即可-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
<!--        <property name="configLocation" value="mybatis-config.xml"/>-->


        <!--类似扫包,该路径下的所有的xml都能获取到,
        这样我们就不用每次有一个mapper我们就要去mybatis-config.xml文件写相应配置:
        如现在有个userMapper.xml的mapper,如果有其他的我们就要写其他的很麻烦:
         <mappers>
        <mapper resource="mapper/userMapper.xml"/>
        ....其他的mapper.xml文件
        </mappers>
        这样太麻烦了,我们不如把mapper.xml都放在同路径,这样就不用mybatis-config.xml了,
        使用mapperLocations,写好对应路径,就能通过该路径找到对应.xml文件,
        就不用去指定配置文件了,不用再去写:
        property name="configLocation" value="mybatis-config.xml"/>
也就可以不需要mybatis-config.xml这个配置文件了(可删除这个文件)
        因为可以帮我找到Mapper.xml的内容去执行sql语句了。
        -->
        <property name="mapperLocations" value="mapper/**/*.xml"/>

        <property name="configuration">
        <bean class="org.apache.ibatis.session.Configuration">
            <property name="mapUnderscoreToCamelCase" value="true"/>
            <property name="logPrefix" value="ydlclass_"/>
        </bean>
       </property>
    </bean>

    <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
        <property name="mapperInterface" value="com.cgboy.mapper.UserMapper" />
        <property name="sqlSessionFactory" ref="sqlSessionFactory" />
    </bean>

    <!--事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${url}"/>
        <property name="driverClassName" value="${driverName}"/>
        <property name="username" value="${user}"/>
        <property name="password" value="${password}"/>
    </bean>


    <!-- 声明式事务 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!-- the transactional semantics... -->
        <tx:attributes>
            <!-- all methods starting with 'get' are read-only -->
            <tx:method name="get*" read-only="true" propagation="SUPPORTS"/>
            <tx:method name="select*" read-only="true" propagation="SUPPORTS"/>
            <!-- other methods use the default transaction settings (see below) -->
            <tx:method name="update*" read-only="false" propagation="REQUIRED"/>
            <tx:method name="delete*" read-only="false" propagation="REQUIRED"/>
            <tx:method name="insert*" read-only="false" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
</beans>

mybatis-config.xml配置:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <typeAliases>
        <typeAlias type="com.cgboy.entity.User" alias="user"/>
    </typeAliases>

    <!--    <mappers>-->
<!--        <mapper resource="mapper/userMapper.xml"/>-->
	<!--    </mappers>-->
</configuration>

userMapper.xml配置:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cgboy.mapper.UserMapper">
    <select id="getUser" resultType="com.cgboy.entity.User">
    select * from `user` where id = #{userId}
    </select>
</mapper>

从sqlsessionfactory工厂拿到sqlsession会话的bean,通过sqlsessionbean去读
mybatis的配置文件(该文件指定了userMapper.xml,userMapper.xml内部有sql语句),根据读取的内容执行了对数据库的操作。

注意:
只需要一个sqlSession的bean,当其他的mapper需要用时将其注入即可

UserMapper接口为对数据库user表的具体操作的内容,user类代表数据库中的user表,

对应接口和类:接口中实现动态代理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4EFZ1nhT-1681790399095)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666700522587.png)]

测试:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xLJI7PRo-1681790399096)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666700667250.png)]

拿到了对应的user信息:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iOWy0fYB-1681790399096)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666700691893.png)]

注解式配置文件和applicationxml配置文件对比:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u0TMRSES-1681790399096)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666710846956.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qscEjBNd-1681790399096)(C:\Users\CG\AppData\Roaming\Typora\typora-user-images\1666710888055.png)]

name=“sqlSessionFactory” ref=“sqlSessionFactory” />

<!--事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="url" value="${url}"/>
    <property name="driverClassName" value="${driverName}"/>
    <property name="username" value="${user}"/>
    <property name="password" value="${password}"/>
</bean>


<!-- 声明式事务 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <!-- the transactional semantics... -->
    <tx:attributes>
        <!-- all methods starting with 'get' are read-only -->
        <tx:method name="get*" read-only="true" propagation="SUPPORTS"/>
        <tx:method name="select*" read-only="true" propagation="SUPPORTS"/>
        <!-- other methods use the default transaction settings (see below) -->
        <tx:method name="update*" read-only="false" propagation="REQUIRED"/>
        <tx:method name="delete*" read-only="false" propagation="REQUIRED"/>
        <tx:method name="insert*" read-only="false" propagation="REQUIRED"/>
    </tx:attributes>
</tx:advice>

mybatis-config.xml配置:

```xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <typeAliases>
        <typeAlias type="com.cgboy.entity.User" alias="user"/>
    </typeAliases>

    <!--    <mappers>-->
<!--        <mapper resource="mapper/userMapper.xml"/>-->
	<!--    </mappers>-->
</configuration>

userMapper.xml配置:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cgboy.mapper.UserMapper">
    <select id="getUser" resultType="com.cgboy.entity.User">
    select * from `user` where id = #{userId}
    </select>
</mapper>

从sqlsessionfactory工厂拿到sqlsession会话的bean,通过sqlsessionbean去读
mybatis的配置文件(该文件指定了userMapper.xml,userMapper.xml内部有sql语句),根据读取的内容执行了对数据库的操作。

注意:
只需要一个sqlSession的bean,当其他的mapper需要用时将其注入即可

UserMapper接口为对数据库user表的具体操作的内容,user类代表数据库中的user表,

对应接口和类:接口中实现动态代理

[外链图片转存中…(img-4EFZ1nhT-1681790399095)]

测试:

[外链图片转存中…(img-xLJI7PRo-1681790399096)]

拿到了对应的user信息:

[外链图片转存中…(img-iOWy0fYB-1681790399096)]

注解式配置文件和applicationxml配置文件对比:

[外链图片转存中…(img-u0TMRSES-1681790399096)][外链图片转存中…(img-qscEjBNd-1681790399096)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值