深入研究Spring-IoC :容器创建的几种方式
来源:互联网 发布:农业物联网大数据平台 编辑:程序博客网 时间:2024/05/29 09:57
1.前言
本文为对tiny-spring的学习解读,代码参考自tiny-spring。一个手写的Spring简易版框架。
前面已经提到了Spring IOC容器的创建大致分为3个步骤。但是这个三个步骤是有一个演进的过程的,Spring容器创建方式前后有6种,从最基本的实例化创建创建到后来的自动化,这些过程的学习对我们学习理解IOC有很大的帮助。
2.容器创建需要的代码
HelloWorldService:
public interface HelloWorldService { void helloWorld();}
HelloWorldServiceImpl:
public class HelloWorldServiceImpl implements HelloWorldService { private String text; private OutputService outputService; @Override public void helloWorld(){ outputService.output(text); } public void setText(String text) { this.text = text; } public void setOutputService(OutputService outputService) { this.outputService = outputService; }}
OutputService:
public interface OutputService { void output(String text);}
OutputServiceImpl:
public class OutputServiceImpl implements OutputService { @Override public void output(String text){ System.out.println(text); }}
tinyioc.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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <bean id="outputService" class="us.codecraft.tinyioc.OutputServiceImpl"> <property name="helloWorldService" ref="helloWorldService"></property> </bean> <bean id="helloWorldService" class="us.codecraft.tinyioc.HelloWorldServiceImpl"> <property name="text" value="Hello World!"></property> <property name="outputService" ref="outputService"></property> </bean> <bean id="beanInitializeLogger" class="us.codecraft.tinyioc.BeanInitializeLogger"> </bean></beans>
3.创建方式演变
1.最基本的容器
IoC最基本的角色有两个:容器(BeanFactory
)和Bean本身。这里使用BeanDefinition
来封装了bean对象,这样可以保存一些额外的元信息。
// 1.初始化beanfactoryBeanFactory beanFactory = new BeanFactory();// 2.注入beanBeanDefinition beanDefinition = new BeanDefinition(new HelloWorldService());beanFactory.registerBeanDefinition("helloWorldService", beanDefinition);// 3.获取beanHelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");helloWorldService.helloWorld();
输出结果为:“Hello World!”
分析:
Spring 通过xml中对Bean类(HelloWorldService)属性的赋值给予了HelloWorldService中的 String text =“Hello World!”,这样OutputServiceImpl调用output()方法时可以输出text的值。
另外这个容器创建的过程:
1.手动实例化最基本的BeanFatory容器接口。
BeanFactory beanFactory = new BeanFactory();
从上一篇博客可以知道BeanFatory有很多实现类,不同的实现类代表的不通过规格的容器,可以实现不同的功能。BanFatory系列可以实现双亲IOC的配置以及Bean的自动配置功能,ApplicaitonContext系列更是增加了面向框架的一些特性。
2.指定BeanDefinition(容器中的数据结构)
BeanDefinition beanDefinition = new BeanDefinition(new HelloWorldService());
BeanDefinition是容器中的抽象Bean结构,是容器为调用方依赖注入时映射的模板,也就是我们在注入原型时就是参考这个抽象的Bean结构。
3.注册BeanDefinition到容器中
beanFactory.registerBeanDefinition("helloWorldService", beanDefinition);
这里调用了beanFatory的registerBeanDefinition()方法,这个注册方法的底层是HashMap实现的,结构上是将我们解析的BeanDefinition以HashMap(key,BeanDefinition)的形式放到BeanFatory中,告诉它都有哪些类Bean在容器里。另外可以通过getBean(key)的形式得到BeanDefinition。
2.将bean创建放入工程且为Bean注入属性
第一个方法中的Bean(HelloWorldService)是初始化好之后再set进去的,实际使用中,我们希望容器来管理bean的创建。于是我们将bean的初始化放入BeanFactory中。为了保证扩展性,我们使用Extract Interface的方法,将BeanFactory
替换成接口,而使用AbstractBeanFactory
和AutowireCapableBeanFactory
作为其实现。”AutowireCapable”的意思是“可自动装配的”,为我们后面注入属性做准备。
// 1.初始化beanfactoryBeanFactory beanFactory = new AutowireCapableBeanFactory();// 2.注入beanBeanDefinition beanDefinition = new BeanDefinition();beanDefinition.setBeanClassName("us.codecraft.tinyioc.HelloWorldService");beanFactory.registerBeanDefinition("helloWorldService", beanDefinition);// 3.设置属性PropertyValues propertyValues = new PropertyValues();propertyValues.addPropertyValue(new PropertyValue("text", "Hello World!"));beanDefinition.setPropertyValues(propertyValues);// 4.获取beanHelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");helloWorldService.helloWorld();
输出结果:“Hello World!”
分析改进点:
1.容器的选择从BeanFatory()改成它的实现类AutowireCapableBeanFactory()可以参考上一篇博客的类图。它拥有装配属性的作用。
2.在载入BeanDefinition时,不再是创建一个Bean类放入其中,这本身就违背了IOC的理念。而是直接指定了BeanDefinition的数据结构模型。
3.调用AutowireCapableBeanFactory()容器的setPropertyValues方法可以为HelloWorldService类指定的属性text手动赋值,而不需要xml中的配置。
3.读取xml配置来初始化Bean
上面为Bean属性注入的部分比较麻烦,如果属性一多,代码会非常麻烦,这里的BeanDefinition
只是一些配置,我们还是用xml来初始化吧。我们定义了BeanDefinitionReader
初始化bean,它有一个实现是XmlBeanDefinitionReader
。
// 1.读取配置XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader());xmlBeanDefinitionReader.loadBeanDefinitions("tinyioc.xml");// 2.初始化BeanFactory并注册beanBeanFactory beanFactory = new AutowireCapableBeanFactory();for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) { beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());}// 3.获取beanHelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");helloWorldService.helloWorld();
分析:
1.读取配置的部分封装的东西比较多。核心问题是如何将xml的Bean配置解析成Spring中的Bean类,可以充当BeanDinfition放到容器中充当数据结构模板。首先是使用xmlBeanDefinitionReader类来读取xml,需要调用Resource接口进行I/O操作,另外在loadBeanDefinitions方法中是先将xm转换成document对象,再放到DefinitionBeanReader中解析,后Spring能识别的Bean形式被BeanDefinitionHolder持有,而BeanDefinitionHolder中就有BeanDefinition。这样就可以注册的容器中。
2.注册的过程有两点,其一,注册其实就将BeanDefinitionHolder中的BeanDefinition放到BeanFatory中。其二,就是map的循环,map的底层Entry实现的。
4.使用高级容器:ApplicationContext
现在BeanFactory的功能齐全了,但是使用起来有点麻烦。于是我们引入熟悉的ApplicationContext
接口,并在AbstractApplicationContext
的refresh()
方法中进行bean的初始化工作。
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("tinyioc.xml");HelloWorldService helloWorldService = (HelloWorldService) applicationContext.getBean("helloWorldService");helloWorldService.helloWorld();
这种方式是我们最常用也是最好的一种方法了,在项目中经常这样写。一是ApplicationContext 除了实现了BeanFatory接口外,还实现了其他高级接口,提供了更多的特性。二是使用ClassPathXmlApplicationContext指定了Resource接口进行IO操作。将所有的解析过程都封装在了底层,而使用者无需手工操作。
- 深入研究Spring-IoC :容器创建的几种方式
- 深入研究Spring-IoC:源码分析容器创建
- Spring--初始化IOC容器的几种方式
- spring IOC容器创建对象的三种方式
- Spring的IOC容器创建过程深入剖析
- spring ioc容器创建过程深入剖析
- 【SSH快速进阶】——Spring IOC容器注入的几种方式
- Spring-- Ioc 容器Bean实例化的几种场景
- Spring IoC容器的深入理解
- spring详解:spring IOC依赖注入的几种方式
- 实例化Spring Ioc容器的三种方式
- Spring IoC容器实例化bean的三种方式
- Spring框架:启动IOC容器的三种方式
- Spring IOC容器-注解的方式
- spring容器与IOC项目的创建
- 深入解读Spring Framework IoC容器(第二弹:依赖注入的方式)
- Spring 容器创建的3种方式
- Spring Ioc 之二 -依赖注入的几种方式
- tensorflow运维(3):tensorflow1.0的一个bug:can't open CUDA library libcupti.so.8.0
- Tomcat8.5源码分析-ContextConfig
- php中curl模拟post提交多维数组
- 对话框
- web测试方法总结(二)
- 深入研究Spring-IoC :容器创建的几种方式
- 用git管理你的代码
- Unicode scalar value
- Linux下部署 jar包
- 如何用万用表检测电路
- Android UI优化调试
- NotePad++设置默认编程语言
- CI框架源码阅读笔记6 扩展钩子 Hook.php
- Java——I/O入门相关练习代码