Spring进阶(回顾,组件,springBean生命周期,bean线程安全,循环依赖,过滤器与拦截器区别)

本文详细介绍了Spring框架的高级主题,包括Spring的回顾,如IOC和AOP概念,以及BeanFactory和ApplicationContext的区别。讨论了SpringBean的生命周期,强调了线程安全问题,指出Spring的单例Bean默认不是线程安全的。同时,解释了Bean的循环依赖解决方案,涉及Spring的三级缓存机制。最后,对比了Servlet过滤器与Spring拦截器的差异,包括它们的实现方式、使用范围和触发时机。
摘要由CSDN通过智能技术生成

Spring进阶

1.1 Spring回顾

spring是一个轻量级的,非侵入式的,IOC,AOP,一站式的,简化企业级开发而生的.

核心包非常小

业务代码中不侵入框架代码

IOC: 控制反转 将生成对象的权利 反转给了spring框架 依赖注入DI 为属性注入值

AOP: 面向切面编程, 将一些与业务代码无关的公共部分抽取出来,使用时,通过代理对象调用,从而达到不修改源代码的基础上增加功能,代码的耦合度降低.

一站式框架: 数据持久层,web控制层…

如何搭建

创建spring配置文件 spring.xml文件

在spring.xml文件中配置 需要让spring管理的类 <bean id class scope …>

spring框架读取xml文件,解析xml

通过工厂模式+反射机制 创建对象 + 代理模式

在需要使用对象时,从spring容器注入对象即可.

spring中常用的注解标签

@component

@Service

spring+jdbc

JdbcTemplate 管理数据源(阿里巴巴 Druid) 事务管理

事务管理的最基本的原理是使用AOP.

声明式事务和编程式事务

事务传播行为 是spring框架自身对事物进行功能上的增强

A 方法 调用 B方法 那么B方法的事务应该如何执行( 把B事务加入到A事务中执行还是 B方法自己创建一个新的独立于A事务)

spring+mybatis

springMVC

执行流程

1.2 BeanFactory 和 ApplicationContext

在 spring 容器中,BeanFactory 接口是 IOC 容器要实现的最基础的接口,定义 了管理 bean 的最基本的方法,例如获取实例、基本的判断等,如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iBd4kAvw-1678757150624)(C:\Users\封纪元\AppData\Roaming\Typora\typora-user-images\1642476511817.png)]在这里插入图片描述

BeanFactory 有多个子接口来进一步扩展 bean 相关的功能

ApplicationContext也间接继承了BeanFactory,如果说BeanFactory是Sping 的心脏,那么 ApplicationContext 就是完整的身躯了。它们都可以当做 Spring 的容器,Spring 容器是生成 Bean 实例的工厂,并管理容器中的 Bean。

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

区别:

1.BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身,是 Spring 中比较原始的Factory,它不支持 AOP、Web 等 Spring 插件. 而 ApplicationContext 不仅包含了 BeanFactory 的所有功能,还支持 Spring 的各种插件,还以一种面向框架的方式工作以及对上下文进行分层和实现继承

2.BeanFactory:需要等到获取某个 bean 的时候才会创建该 bean,即延迟初 始化.

ApplicationContext:面向应用的,增加了功能(支持AOP 事务), 适合与web应用程序,在服务器启动时就创建.在启动 Spring 容器时就会创建所有的 bean(Web 应 用中推荐)

1.3 springBean 的生命周期

一个对象什么时候生(创建) 什么时候销毁

spring中的bean可能经过5个阶段

1.实例化 Instantiation 创建一个原始的对象 例如 new对象 通过反射机制实现的(框架可以读到类名)

2.属性赋值 Populate 为对象的属性进行赋值

​ UserService

​ 注入UserDao userDao

3.初始化 Initialization 最早在Serlvet 先创建一个对象 然后调用init()进行初始化

​ 我们的bean如果实现了某些接口,就可以去执行这些方法,用来初始化我们的对象重点在于对类进行功能提升.

​ 如果此类有增强(aop),就是在此处为bean添加功能.

4.将 bean 对象放入到容器中,使用

5.销毁 Destruction

细化:

1.instantiate bean 对象实例化

2.populate properties 属性赋值

3.1 如果 Bean 实现 BeanNameAware 执行 setBeanName

3.2 如果 Bean 实现 BeanFactoryAware 或者 ApplicationContextAware 设置工厂 setBeanFactory 或者上下文对象 setApplicationContext 对象. 初始化

3.3 如果存在类实现 BeanPostProcessor(AOP) ,执行 postProcessBeforeInitialization

3.4 如果 Bean 实现 InitializingBean 执行 afterPropertiesSet 如果配置了自己的初始化方法

3.5 如果存在类实现 BeanPostProcessor(AOP) ,执行 postProcessAfterInitialization

4.完整的 bean 创建好,将 bean 对象放入到容器中,可以使用

5.销毁 如果 Bean 实现 DisposableBean 执行 destroy

如果配置了自己的销毁方法 指定销毁方法customerDestroy.

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

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

1.4 Spring 中的 bean 是线程安全的吗?

Servlet是线程安全的吗?

serlvet是线程不安全的

servlet是单例的还是多例的?

是单例 com.

在服务器启动时由服务器创建,只创建了一个

Spring中的Bean不是线程安全的

Spring 容器中的 Bean 是否线程安全,容器本身并没有提供 Bean 的线程安全策 略,因此可以说 Spring 容器中的 Bean 本身不具备线程安全的特性,但是具体 还是要结合具体 scope 的 Bean 情况。

Spring 的 bean 作用域(scope)类型

1、singleton:单例,默认作用域。

2、prototype:原型,每次创建一个新对象。

3、request:请求,每次 Http 请求创建一个新对象,适用于

线程安全这个问题,要从单例与原型 Bean 分别进行说明。

原型 Bean:

  • 对于原型 Bean,每次创建一个新对象,也就是线程之间并不存在 Bean 共享,自然是不会有线程安全的问题。

  • 单例 Bean:对于单例 Bean,所有线程都共享一个单例实例 Bean,因此是存在资源的竞争,所以是线程不安全的

Bean 又分为

有状态就是有数据存储功能(例如包含成员变量) (线程不安全)

无状态就是不会保存数据 (线程安全)

如果单例 Bean,是一个无状态 Bean,也就是线程中的操作不会对 Bean 的成员执行查 询以外的操作,那么这个单例 Bean 是线程安全的。比如 Spring mvc 的 Controller、 Service、Dao 等,这些 Bean 大多是无状态的,只关注于方法本身。

但是如果 Bean 是有状态的 那就需要开发人员自己来进行线程安全的保证,最简单 的办法就是改变 bean 的作用域 把 "singleton"改为’‘protopyte’ 这样每次请求 Bean 就相当于是 new Bean() 这样就可以保证线程的安全了。

controller、service 和 dao 层本身并不是线程安全的,只是如果只是调用里面的方法, 而且多线程调用一个实例的方法,会在内存中复制变量,这是自己的线程的工作内存,是安全的。

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

1.5 Bean 循环依赖

JAVA 中循环依赖场景

很简单,就是 A 对象依赖了 B 对象,B 对象依赖了 A 对象。

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

那么循环依赖是个问题吗?

如果不考虑 Spring,循环依赖并不是问题,因为对象之间相互依赖是很正常的 事情。

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

这样A,B就依赖上了

但是,在 Spring 中循环依赖就是一个问题了,为什么?

​ 因为,在 Spring 中,一个对象并不是简单 new 出来了,而是会经过一系列的 Bean 的生命周期,就是因为 Bean 的生命周期所以才会出现循环依赖问题。当 然,在 Spring 中,出现循环依赖的场景很多,有的场景 Spring 自动帮我们解 决了,而有的场景则需要程序员来解决。

产生循环依赖的问题,主要是:A 创建时–>需要 B----B去创建—>需要 A,从 而产生了循环

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

怎么解决呢?

spring 内部有三级缓存:

每一个缓存可以理解为一个map容器(把不同的对象做一个临时存储)

一级缓存: 存放创建,初始化完成的完整的bean.

二级缓存: 存储原始的对象

三级缓存: 假如B类如果有需要增强的功能,那么把这个半成品的B对象继续放在3级缓存中去增强功能.

三级缓存详解:

singletonObjects 一级缓存,用于保存实例化、注入、初始化完成的 bean 实 例

earlySingletonObjects 二级缓存,用于保存实例化完成的 bean 实例

singletonFactories 三级缓存,用于保存 bean 创建工厂,以便于后面扩展有机会创建代理对象

A,B 循环依赖,先初始化 A,先暴露一个半成品 A,再去初始化依赖的 B,初 始化 B 时如果发现 B 依赖 A,也就是循环依赖,就注入半成品 A,之后初始化 完毕 B,再回到 A 的初始化过程时就解决了循环依赖,在这里只需要一个 Map 能缓存半成品 A 就行了,也就是二级缓存就够了,但是这个二级缓存存的是 Bean 对象,如果这个对象存在代理,那应该注入的是代理,而不是 Bean,此时二级 缓存无法及缓存 Bean,又缓存代理,因此三级缓存做到了缓存 工厂 ,也就是 生成代理,这我的理解:总结起来:二级缓存就能解决缓存依赖,三级缓存解决 的是代理。

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

1.6 Servlet 的过滤器与 Spring 拦截器区别

区别主要在底层实现方式上有所不同:

过滤器实现是依赖于tomcat,请求会先到达过滤器,然后进入Servlet.

spring拦截器: 是框架内部封装的, 请求是先到达servlet, 根据映射地址,去匹配拦截器,最终到达控住器

实现原理不同

  • 过滤器和拦截器 底层实现方式大不相同,过滤器 是基于函数回调的,
  • 拦截器 则 是基于 Java 的反射机制(动态代理)实现的。

使用范围不同

  • 我们看到过滤器 实现的是 javax.servlet.Filter 接口,而这个接口是在 Servlet 规范中定义的,也就是说过滤器 Filter 的使用要依赖于 Tomcat 等容器,导致 它只能在 web 程序中使用。

触发时机不同

过滤器 和 拦截器的触发时机也不同,我们看下边这张图。

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

  • 过滤器 Filter 是在请求进入容器后,但在进入 servlet 之前进行预处理,请求结 束是在 servlet 处理完以后。
  • 拦截器 Interceptor 是在请求进入 servlet 后,在进入 Controller 之前进行预 处理的,Controller 中渲染了对应的视图之后请求结束。

拦截的请求范围不同

  • 过滤器几乎可以对所有进入容器的请求起作用
  • 拦截器只会对 Controller 中请求或访问 static 目录下的资源请求起作用。

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值