谈谈 SpringFramework 与 IoC 依赖查找
生活不会按照你想要的方式进行,它会给你一段时间,让你孤独又迷惘,等你度过低潮,那些独处的时光必定能照亮你的路。走得最急的,都是最美的风景;伤得最深的,也总是那些最真的感情。收拾起心情,继续向前走,就会发现:错过花,你将收获雨,错过雨,你会遇到彩虹。
1. 面试题
先说下该篇文章可延伸出的面试题.
1. 谈谈 SpringFramework / 说说你理解的 SpringFramework
SpringFramework 是一个开源的、松耦合的、分层的、可配置的一站式企业级 Java 开发框架,它的核心是 IOC 与 AOP ,它可以更容易的构建出企业级 Java 应用,并且它可以根据应用开发的组件需要,整合对应的技术。
松耦合的: 为了描述 IOC 和 AOP, 可能会延伸出 IOC 松耦合相关内容可配置: 给后面的 SpringBoot(约定大于配置)做铺垫 IOC 与 AOP: Inverse of Control 控制反转、Aspect Oriented Programming 面向切面编程
2. 为何使用 SpringFramework
可通过如下几点进行描述:
IOC 实现了组件之间的解耦
AOP 切面编程将应用业务做统一或特定的功能增强, 可实现应用业务与增强逻辑的解耦
容器管理应用中使用的 Bean、托管 Bean 的生命周期、事件与监听的驱动机制
Web、事务控制、测试、与其他技术的整合
3. SpringFramework 包含哪些模块?
beans、core、context、expression 【核心包】
aop 【切面编程】
jdbc 【整合 jdbc 】
orm 【整合 ORM 框架】
tx 【事务控制】
web 【 Web 层技术】
test 【整合测试】
......
4. 依赖查找与依赖注入的对比
作用目标实现方式依赖查找(DL)通常是类成员使用上下文(容器)主动获取依赖注入(DI)可以是方法体内也可以是方法体外借助上下文被动的接收
5. BeanFactory 与 ApplicationContext 的对比
BeanFactory 接口提供了一个抽象的配置和对象的管理机制,
ApplicationContext 是 BeanFactory 的子接口,它简化了与 AOP 的整合、消息机制、事件机制,以及对 Web 环境的扩展( WebApplicationContext 等)
ApplicationContext 主要扩展了以下功能:
AOP 的支持(
AnnotationAwareAspectJAutoProxyCreator作用于 Bean 的初始化之后 )配置元信息(
BeanDefinition、Environment、注解等 )资源管理(
Resource抽象 )事件驱动机制(
ApplicationEvent、ApplicationListener)消息与国际化(
LocaleResolver)Environment抽象( SpringFramework 3.1 以后)
2. SpringFramework 发展史
在 Spring 技术之前,J2EE 兴起,当时的 J2EE 学习成本极高,开发速度慢,开发出来的程序性能消耗也高,已经跟不上当时应用程序的需要。在 2002 年,Rod Johnson 写了一本书名为《Expert One-on-One J2EE design and development》 ,书中对当时现有的 J2EE 应用的架构和 EJB 框架存在的臃肿、低效等问题提出了质疑,并且积极寻找和探索解决方案。
基于普通 Java 类和依赖注入的思想提出了更为简单的解决方案,这便是 Spring 框架核心思想的萌芽
过了 2 年,2004 年 SpringFramework 1.0.0 横空出世,随后 Rod Johnson 又写了一本书**《Expert one-on-one J2EE Development without EJB》**,当时在 J2EE 开发界引起了巨大轰动,这本书中直接告诉开发者完全可以不使用 EJB 开发 J2EE 应用,而是可以换用一种更轻量级、更简单的框架来代替,那就是 SpringFramework 。
那时在开发界是种种的质疑,大概是这样的,纳尼? 质疑 IBM 诸多大佬的设计精华,这个是什么人?为何如此嚣张? 而后 还是被一些开发者尝试使用了,使用后发现确实要比 EJB 好用,不那么臃肿,性能也有所改善,提供的一些特性也优于 EJB,于是就慢慢转投 SpringFramework
下面展示下 SpringFramework 重要版本的更新时间及主要特性
SpringFramework 版本对应 jdk 版本重要特性 SpringFramework 1.xjdk 1.3 基于 xml 的配置 SpringFramework 2.xjdk 1.4 改良 xml 文件、初步支持注解式配置 SpringFramework 3.xJava 5 注解式配置、JavaConfig 编程式配置、Environment 抽象 SpringFramework 4.xJava 6SpringBoot 1.x、核心容器增强、条件装配、WebMvc 基于 Servlet3.0SpringFramework 5.xJava 8SpringBoot 2.x、响应式编程、SpringWebFlux、支持 Kotlin
3. IOC 依赖查找
基础框架搭建
创建 Maven 模块,这里以
ioc-learning为例引入依赖
创建配置文件
ioc-learning-dl.xml
声明普通类
Person.java
ioc-learning-dl.xml配置文件加入Persion的声明
创建启动类
运行打印
成功打印出 Person 的全限定类名 + 内存地址,证明编写成功。
3.1 byName 名称查找
上述基础框架中的步骤 6
核心代码
3.2 byType 类型查找
1. 普通类
修改配置文件
ioc-learning-dl.xml将person的声明中id属性去掉
修改启动类
getBean方法参数中直接传入Class类型 返回值也无需再进行强转
运行
main方法 打印如下
2. 接口
创建接口
demoDao以及 实现类DemoDaoImpl
修改配置文件
ioc-learning-dl.xml加入DemoDaoImpl的声明
修改启动类
运行
main方法 打印结果如下
由此可见 DemoDaoImpl 注入成功 并且BeanFactory可以根据接口类型找到对应的实现类
3.3 高级查找
ofType 根据类型查找多个
如果一个接口有多个实现类,如何一次性的把所有的实现类都取出来呢? 前面用到的getBean方法显然无法满足 需使用到ofType方法
继上面的代码 创建 2 个
DemoDao的实现类 如下
修改配置文件
ioc-learning-dl.xml加入新建的两个实现类的声明
修改启动类
运行main方法 打印结果如下
细心的小伙伴可能会发现 为何这里读取配置文件的返回值使用的是ApplicationContext 而不使用BeanFactory
ApplicationContext 也是一个接口,通过 IDEA 的diagram查看类的继承链,可以看到该接口继承了BeanFactory
官方文章中有这样的解释:
org.springframework.beans 和 org.springframework.context 包是 SpringFramework 的 IOC 容器的基础。BeanFactory 接口提供了一种高级配置机制,能够管理任何类型的对象。ApplicationContext 是 BeanFactory 的子接口。它增加了:
与 SpringFramework 的 AOP 功能轻松集成
消息资源处理(用于国际化)
事件发布
应用层特定的上下文,例如 Web 应用程序中使用的
WebApplicationContext
如此说来 ApplicationContext 包含了 **BeanFactory 的所有功能,**并且还扩展了更多的特性
其实对于我们目前的最主要原因是BeanFactory 中木有getBeansOfType()这个方法~~~
withAnnotation 根据注解查找
IOC 容器还可以根据类上标注的注解来查找对应的 Bean
创建一个注解类
创建几个 bean 对象
其中只有Xiaoming这个类没有添加@Animal注解
修改 XML 配置文件,添加如下三个声明
修改启动类
运行
main方法 打印结果如下
延迟查找
对于一些特殊场景,需要依赖容器中某些特定的 bean 但是当他们不存在时如何使用默认/或者缺省策略来处理逻辑呢?
这里我们先把 xml 配置文件中的 Dog 的声明暂时删掉
这样我们在获取 dog 的时候ctx.getBean(Dog.class) 就会报错 NoSuchBeanDefinitionException
现有方案启用缺省策略
这里我们把业务代码写在了 catch 代码块中,不够优雅,性能也有待改善,而且如果后期每个 bean 都这样处理,代码量巨大
改造下 获取之前检查
这里使用到了ApplicationContext中的方法 containsBean 用于检查容器中是否有指定的 bean
该方法看似已经没有问题了,但是要考虑到该方法传递的参数只能传递 bean 的 id 不能按照 bean 的类型去查找 如果 bean 的名字是其他的呢,工作量还是巨大的
使用延迟查找
该机制的大概思路为 当我们想要获取一个 Bean 的时候,先返回给我们一个包装类,等到我们真正去使用的时候再去“拆包”检查里面到底有没有该 Bean 对象
使用方法如下
上面代码可以看到 就是按照前面的思路进行处理的,返回了一个“包装”给我们,当我们使用的时候直接调用getObject方法
但如果 容器中没有该 Bean 还是会报 NoSuchBeanDefinitionException ,下面会介绍下ObjectProvider提供的其他方法
getIfAvailable()该方法可以在找不到 Bean 的时候返回 null 而不抛出异常ifAvailable()该方法是在取到 Bean 后马上或者间歇的使用
以上就是关于 SpringFramework 以及 IoC 的依赖查找相关内容,小伙伴可以再去顶部查看下面试题,是否都可以理解了并且掌握了呢.











评论