千家信息网

什么是IOC容器设计理念以及源码怎么写

发表于:2024-12-12 作者:千家信息网编辑
千家信息网最后更新 2024年12月12日,什么是IOC容器设计理念以及源码怎么写,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。⼀、IOC核⼼理论回顾知识点:1. Ioc理念概要2
千家信息网最后更新 2024年12月12日什么是IOC容器设计理念以及源码怎么写

什么是IOC容器设计理念以及源码怎么写,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

⼀、IOC核⼼理论回顾
知识点:
1. Ioc理念概要
2. 实体Bean的创建
3. Bean的基本特性
4. 依赖注⼊
1、Ioc理论概要
在JAVA的世界中,⼀个对象A怎么才能调⽤对象B?通常有以下⼏种⽅法。
类别描述时间点
外部传⼊
构造⽅法传⼊创建引⽤对象时
属性设置传⼊设置对象状态时
运⾏时做为参数传⼊调⽤时
内部创建
属性中直接创建创建引⽤对象时
初始化⽅法创建创建引⽤对象时
运⾏时动态创建调⽤时
上表可以看到, 引⽤⼀个对象可以在不同地点(其它引⽤者)、不同时间由不同的⽅法完
成。如果B只是⼀个⾮常简单的对象 如直接new B(),怎样都不会觉得复杂,⽐如你从来不会
觉得创建⼀个St ring 是⼀个件复杂的事情。但如果B 是⼀个有着复杂依赖的Service对象,这
时在不同时机引⽤B将会变得很复杂。
⽆时⽆刻都要维护B的复杂依赖关系,试想B对象如果项⽬中有上百过,系统复杂度将会成陪
数增加。
IOC容器的出现正是为解决这⼀问题,其可以将对象的构建⽅式统⼀,并且⾃动维护对象的依
赖关系,从⽽降低系统的实现成本。前提是需要提前对⽬标对象基于XML进⾏声明。
2、实体Bean的构建
a. 基于Class构建
b. 构造⽅法构建
c. 静态⼯⼚⽅法创建
d. Fact oryBean创建
1、基于ClassName构建
这是最常规的⽅法,其原理是在spring底层会基于class 属性 通过反射进⾏构建。
2、构造⽅法构建
如果需要基于参数进⾏构建,就采⽤构造⽅法构建,其对应属性如下:
name:构造⽅法参数变量名称
t ype:参数类型
index:参数索引,从0开始
value:参数值,spring 会⾃动转换成参数实际类型值
ref :引⽤容串的其它对象
3、静态⼯⼚⽅法创建

1
2
3
4

1
2
3

如果你正在对⼀个对象进⾏A/B测试 ,就可以采⽤静态⼯⼚⽅法的⽅式创建,其于策略
创建不同的对像或填充不同的属性。
该模式下必须创建⼀个静态⼯⼚⽅法,并且⽅法返回该实例,spring 会调⽤该静态⽅法
创建对象。
4、Fact oryBean创建
指定⼀个Bean⼯⼚来创建对象,对象构建初始化 完全交给该⼯⼚来实现。配置Bean时指定该
⼯⼚类的类名。
3、bean的基本特性
???? 作⽤范围
???? ⽣命周期
???? 装载机制
public static HelloSpring build(1 String type) {
2 if (type.equals("A")) {
3 return new HelloSpring("luban", "man");
4 } else if (type.equals("B")) {
5 return new HelloSpring("diaocan", "woman");
6 } else {
7 throw new IllegalArgumentException("type must A or B");
8 }
9 }
1
2
3

1 public class DriverFactoryBean implements FactoryBean {
2 private String jdbcUrl;
3 public Object getObject() throws Exception {
4 return DriverManager.getDriver(jdbcUrl);
5 }
6 public Class getObjectType() {
7 return Driver.class;
8 }
9 public boolean isSingleton() {
10 return true;
11 }
12 public String getJdbcUrl() {
13 return jdbcUrl;
14 }
15 public void setJdbcUrl(String jdbcUrl) {
16 this.jdbcUrl = jdbcUrl;
17 }
18 }
a、作⽤范围
很多时候Bean对象是⽆状态的 ,⽽有些⼜是有状态的 ⽆状态的对象我们采⽤单例即可,⽽有
状态则必须是多例的模式,通过scope 即可创建
scope="prot ot ype"
scope="singlet on"
如果⼀个Bean设置成 prot ot ype 我们可以 通过BeanFact oryAware 获取 BeanFact ory 对象
即可每次获取的都是新对像。
b、⽣命周期
Bean对象的创建、初始化、销毁即是Bean的⽣命周期。通过 init -met hod、dest roymet
hod 属性可以分别指定期构建⽅法与初始⽅法。
如果觉得麻烦,可以让Bean去实现 Init ializingBean.af t erPropert iesSet ()、
DisposableBean.dest roy()⽅法。分别对应 初始和销毁⽅法
c、加载机制
指示Bean在何时进⾏加载。设置lazy-init 即可,其值如下:
t rue: 懒加载,即延迟加载
f alse:⾮懒加载,容器启动时即创建对象
def ault :默认,采⽤def ault -lazy-init 中指定值,如果def ault -lazy-init 没指定就是
f alse
什么时候使⽤懒加载?
懒加载会容器启动的更快,⽽⾮懒加载可以容器启动时更快的发现程序当中的错误 ,选择哪
⼀个就看追求的是启动速度,还是希望更早的发现错误,⼀般我们会选 择后者。
4、依赖注⼊
试想IOC中如果没有依赖注⼊,那这个框架就只能帮助我们构建⼀些简单的Bean,⽽之前所说
的复杂Bean的构建问题将⽆法解决,spring这个框架不可能会像现在这样成功。 spring 中
ioc 如何依赖注⼊呢。有以下⼏种⽅式:
1. set⽅法注⼊
2. 构造⽅法注⼊
3. ⾃动注⼊(byName、byT ype)
4. ⽅法注⼊(lookup-met hod)
1、set⽅法注⼊
1 scope="prototype
2
3


1
1 2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
3
4 default-lazy-init="true">
2、构造⽅法注⼊
3、⾃动注⼊(byName\byT ype\const ruct or)
byName:基于变量名与bean 名称相同作为依据插⼊
byT ype:基于变量类别与bean 名称作
const ruct or:基于IOC中bean 与构造⽅法进⾏匹配(语义模糊,不推荐)
4、依赖⽅法注⼊(lookup-met hod)
当⼀个单例的Bean,依赖于⼀个多例的Bean,⽤常规⽅法只会被注⼊⼀次,如果每次都
想要获取⼀个全新实例就可以采⽤lookup-met hod ⽅法来实现。
该操作的原理是基于动态代理技术,重新⽣成⼀个继承⾄⽬标类,然后重写抽像⽅法到达注⼊
⽬的。
前⾯说所单例Bean依赖多例Bean这种情况也可以通过实现 Applicat ionCont ext Aware 、
BeanFact oryAware 接⼝来获取BeanFact ory 实例,从⽽可以直接调⽤get Bean⽅法获取新实
例,推荐使⽤该⽅法,相⽐lookup-met hod语义逻辑更清楚⼀些。
⼆、IOC 设计原理与实现

2
3

1
2
3
4

5

class="com.tuling.spring.HelloSpring" autowire="byName">
1
2

1 #编写一个抽像类
2 public abstract class MethodInject {
3 public void handlerRequest() {
4 // 通过对该抽像方法的调用获取最新实例
5 getFine();
6 }
7 # 编写一个抽像方法
8 public abstract FineSpring getFine();
9 }
10 // 设定抽像方法实现
11
12
13

知识点:
1、源码学习的⽬标
2、Bean的构建过程
3、BeanFact ory与Applicat ionCont ext区别
1、源码学习⽬标:
不要为了读书⽽读书,同样不要为了阅读源码⽽读源码。没有⽬的⼀头扎进源码的⿊森林
当中很快就迷路了。到时就不是我们读源码了,⽽是源码'毒'我们。毕竟⼀个框架是由专业团
队,历经N次版本迭代的产物,我们不能指望像读⼀本书的⽅式去阅读它。 所以必须在读源码
之前找到⽬标。是什么呢?
⼤家会想,读源码的⽬标不就是为了学习吗?这种⽬标太过抽像,⽬标⽆法验证。通常我
们会设定两类型⽬标:⼀种是对源码进⾏改造,⽐如添加修改某些功能,在实现这种⽬标的过
程当中⾃然就会慢慢熟悉了解该项⽬。但然这个难度较⼤,耗费的成本也⼤。另⼀个做法是
⾃⼰提出⼀些问题,阅读源码就是为这些问题寻找答案。以下就是我们要⼀起在源码中寻找答
案的问题:
1. Bean⼯⼚是如何⽣产Bean的?
2. Bean的依赖关系是由谁解来决的?
3. Bean⼯⼚和应⽤上⽂的区别?
2、Bean的构建过程
spring.xml ⽂件中保存了我们对Bean的描述配置,BeanFact ory 会读取这些配置然后⽣
成对应的Bean。这是我们对ioc 原理的⼀般理解。但在深⼊⼀些我们会有更多的问题?
1. 配置信息最后是谁JAVA中哪个对象承载的?
2. 这些承载对象是谁业读取XML⽂件并装载的?
3. 这些承载对象⼜是保存在哪⾥?
BeanDefinit ion (Bean定义)
ioc 实现中 我们在xml 中描述的Bean信息最后 都将保存⾄BeanDefinit ion (定义)对象中,
其中xml bean 与BeanDefinit ion 程⼀对⼀的关系。
由此可⻅,xml bean中设置的属性最后都会体现在BeanDefinit ion中。如:
演示查看 BeanDefinit ion 属性结构
BeanDefinit ionRegist ry(Bean注册器)
在上表中我们并没有看到 xml bean 中的 id 和name属性没有体现在定义中,原因是ID 其作
为当前Bean的存储key注册到了BeanDefinit ionRegist ry 注册器中。name 作为别名key 注册
到了 AliasRegist ry 注册中⼼。其最后都是指向其对应的BeanDefinit ion。
演示查看 BeanDefinit ionRegist ry属性结构
XML-bean BeanDefinit ion
class beanClassName
scope scope
lazy-init lazyInit
const ruct or-arg Const ruct orArgument
propert y MutablePropertyValues
f act ory-met hod f actoryMethodName
dest roy-met hod Abst ract BeanDefinit ion.dest royMet hodName
init -met hod Abst ract BeanDefinit ion.init Met hodName
aut owire Abst ract BeanDefinit ion.aut owireMode
id
name
????
????
BeanDefinit ionReader(Bean定义读取)
⾄此我们学习了 BeanDefinit ion 中存储了Xml Bean信息,⽽BeanDefinit ionRegist er 基于ID
和name 保存了Bean的定义。接下要学习的是从xml Bean到BeanDefinit ion 然后在注册⾄
BeanDefinit ionRegist er 整个过程。
上图中可以看出Bean的定义是由BeanDefinit ionReader 从xml 中读取配置并构建出
BeanDefinit ionReader,然后在基于别名注册到BeanDefinit ionRegist er中。
查看BeanDefinit ???? ionReader结构
⽅法说明:
???? loadBeanDefinit ions(Resource resource)
???? 基于资源装载Bean定义并注册⾄注册器
???? int loadBeanDefinit ions(St ring locat ion)
???? 基于资源路径装载Bean定义并注册⾄注册器
???? BeanDefinit ionRegist ry get Regist ry()
???? 获取注册器
???? ResourceLoader get ResourceLoader()
???? 获取资源装载器
基于示例演示BeanDefinit ionReader装载过程
Beanf act ory(bean ⼯⼚)
有了Bean的定义就相当于有了产品的配⽅,接下来就是要把这个配⽅送到⼯⼚进⾏⽣产了。
在ioc当中Bean的构建是由BeanFact ory 负责的。其结构如下:
????
1 //创建一个简单注册器
2 BeanDefinitionRegistry register = new SimpleBeanDefinitionRegistry();
3 //创建bean定义读取器
4 BeanDefinitionReader reader = new XmlBeanDefinitionReader(register);
5 // 创建资源读取器
6 DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
7 // 获取资源
8 Resource xmlResource = resourceLoader.getResource("spring.xml");
9 // 装载Bean的定义
10 reader.loadBeanDefinitions(xmlResource);
11 // 打印构建的Bean 名称
12 System.out.println(Arrays.toString(register.getBeanDefinitionNames());
⽅法说明:
???? get Bean(St ring)
???? 基于ID或name 获取⼀个Bean
???? T get Bean(Class requiredT ype)
???? 基于Bean的类别获取⼀个Bean(如果出现多个该类的实例,将会报错。但可以指定
primary="t rue" 调整优先级来解决该错误 )
???? Object get Bean(St ring name, Object ... args)
???? 基于名称获取⼀个Bean,并覆盖默认的构造参数
???? boolean isT ypeMat ch(St ring name, Class t ypeT oMat ch)
???? 指定Bean与指定Class 是否匹配
`
以上⽅法中重点要关注get Bean,当⽤户调⽤get Bean的时候就会触发 Bean的创建动作,其
是如何创建的呢?
演示基???? 本BeanFactory获取⼀个Bean
1 #创建Bean堆栈
2 // 其反射实例化Bean
3 java.lang.reflect.Constructor.newInstance(Unknown Source:-1)
4 BeanUtils.instantiateClass()
5 //基于实例化策略 实例化Bean
6 SimpleInstantiationStrategy.instantiate()
7 AbstractAutowireCapableBeanFactory.instantiateBean()
8 // 执行Bean的实例化方法
9 AbstractAutowireCapableBeanFactory.createBeanInstance()
10 AbstractAutowireCapableBeanFactory.doCreateBean()
11 // 执行Bean的创建
12 AbstractAutowireCapableBeanFactory.createBean()
13 // 缓存中没有,调用指定Bean工厂创建Bean
14 AbstractBeanFactory$1.getObject()
15 // 从单例注册中心获取Bean缓存
16 DefaultSingletonBeanRegistry.getSingleton()
17 AbstractBeanFactory.doGetBean()
Bean创建时序图:
从调⽤过程可以总结出以下⼏点:
1. 调⽤BeanFact ory.get Bean() 会触发Bean的实例化。
2. Def ault Singlet onBeanRegist ry 中缓存了单例Bean
3. Bean的创建与初始化是由Abst ract Aut owireCapableBeanFact ory 完成的。
3、BeanFactory 与 ApplicationContext区别
BeanFact ory 看下去可以去做IOC当中的⼤部分事情,为什么还要去定义⼀个
Applicat ionCont ext 呢?
Applicat ionCont ext 结构图
从图中可以看到 Applicat ionCont ext 它由BeanFact ory接⼝派⽣⽽来,因⽽提供了
BeanFact ory所有的功能。除此之外cont ext包还提供了以下的功能:
1. MessageSource, 提供国际化的消息访问
2. 资源访问,如URL和⽂件
3. 事件传播,实现了Applicat ionList ener接⼝的bean
4. 载⼊多个(有继承关系)上下⽂ ,使得每⼀个上下⽂都专注于⼀个特定的层次,⽐如应⽤
的web层
总结回顾:
BeanDefinit ion
Def ault ResourceLoader
XmlBeanDefinit ionReader
BeanDefinit ionRegist ry
18 // 获取Bean
19 AbstractBeanFactory.getBean()
20 // 调用的客户类
21 com.tuling.spring.BeanFactoryExample.main()
BeanFact ory
Def ault List ableBeanFact ory
Aut owireCapableBeanFact ory
Abst ract Aut owireCapableBeanFact ory
Singlet onBeanRegist ry
Def ault Singlet onBeanRegist ry

看完上述内容,你们掌握什么是IOC容器设计理念以及源码怎么写的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注行业资讯频道,感谢各位的阅读!

对象 源码 实例 属性 参数 问题 复杂 装载 容器 不同 方法 资源 过程 名称 就是 是由 状态 结构 静态 学习 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 微信里的人工服务器在什么地方找 旅游网络软件开发公司 进销存软件数据库设计 三级网络技术需要买书吗 苏州电子网络技术怎么样 中专 网络技术专业 课程 四川迈云网络技术有限公司 网络安全法网站管理者 信息与网络技术能报考二建吗 成都百微软件开发有限公司招聘 php连接数据库查询界面 生产管理数据库排名 商家打印订单显示请求服务器超时 数据库表关系用什么软件画 越南服务器代理ip客服 高级网络技术工程师工资 云服务器可以用来训练人工智能吗 青浦区海航软件开发定制价格 网络技术专业毕业实习报告 海致网络技术有限 医院网络安全总则 智好网络技术有限公司怎么样 linux 同步数据库 网络安全法后续 生产管理数据库排名 三个以上常用的数据库 长沙计算网络技术学院多少分 数据库删除表快捷键 网络安全股票排行榜 智慧校园网络技术
0