本文为对tiny-spring的学习解读,代码参考自tiny-spring。一个手写的Spring简易版框架。
前面已经提到了Spring IOC容器的创建大致分为3个步骤。但是这个三个步骤是有一个演进的过程的,Spring容器创建方式前后有6种,从最基本的实例化创建创建到后来的自动化,这些过程的学习对我们学习理解IOC有很大的帮助。
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>
IoC最基本的角色有两个:容器(BeanFactory
)和Bean本身。这里使用BeanDefinition
来封装了bean对象,这样可以保存一些额外的元信息。
// 1.初始化beanfactory
BeanFactory beanFactory = new BeanFactory();
// 2.注入bean
BeanDefinition beanDefinition = new BeanDefinition(new HelloWorldService());
beanFactory.registerBeanDefinition("helloWorldService", beanDefinition);
// 3.获取bean
HelloWorldService 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。
第一个方法中的Bean(HelloWorldService)是初始化好之后再set进去的,实际使用中,我们希望容器来管理bean的创建。于是我们将bean的初始化放入BeanFactory中。为了保证扩展性,我们使用Extract Interface的方法,将BeanFactory
替换成接口,而使用AbstractBeanFactory
和AutowireCapableBeanFactory
作为其实现。”AutowireCapable”的意思是“可自动装配的”,为我们后面注入属性做准备。
// 1.初始化beanfactory
BeanFactory beanFactory = new AutowireCapableBeanFactory();
// 2.注入bean
BeanDefinition 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.获取bean
HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");
helloWorldService.helloWorld();
输出结果:“Hello World!”
分析改进点:
1.容器的选择从BeanFatory()改成它的实现类AutowireCapableBeanFactory()可以参考上一篇博客的类图。它拥有装配属性的作用。
2.在载入BeanDefinition时,不再是创建一个Bean类放入其中,这本身就违背了IOC的理念。而是直接指定了BeanDefinition的数据结构模型。
3.调用AutowireCapableBeanFactory()容器的setPropertyValues方法可以为HelloWorldService类指定的属性text手动赋值,而不需要xml中的配置。
上面为Bean属性注入的部分比较麻烦,如果属性一多,代码会非常麻烦,这里的BeanDefinition
只是一些配置,我们还是用xml来初始化吧。我们定义了BeanDefinitionReader
初始化bean,它有一个实现是XmlBeanDefinitionReader
。
// 1.读取配置
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader());
xmlBeanDefinitionReader.loadBeanDefinitions("tinyioc.xml");
// 2.初始化BeanFactory并注册bean
BeanFactory beanFactory = new AutowireCapableBeanFactory();
for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) {
beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
}
// 3.获取bean
HelloWorldService 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实现的。
现在BeanFactory的功能齐全了,但是使用起来有点麻烦。于是我们引入熟悉的ApplicationContext
接口,并在AbstractApplicationContext
的refresh()
方法中进行bean的初始化工作。
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("tinyioc.xml");
HelloWorldService helloWorldService = (HelloWorldService) applicationContext.getBean("helloWorldService");
helloWorldService.helloWorld();
这种方式是我们最常用也是最好的一种方法了,在项目中经常这样写。一是ApplicationContext 除了实现了BeanFatory接口外,还实现了其他高级接口,提供了更多的特性。二是使用ClassPathXmlApplicationContext指定了Resource接口进行IO操作。将所有的解析过程都封装在了底层,而使用者无需手工操作。
在这个lab中,你会在多个同时active的用户模式环境中实现preemptive multitasking(抢占多任务处理)在Part A,你会向JOS加入multiprocessor support(多处理器支持),实现round-robin scheduling(轮转调度),并且添加基础的environment management system calls(这个调用能创建和destroy...
<!DOCTYPE html><html> <head> <meta charset="utf-8"> <title>文字多余部分隐藏</title> <style> .content { width: 300px; height: 100px; .
点击上方蓝色“程序猿DD”,选择“设为星标”回复“资源”获取独家整理的学习资料!来源 |juejin.im/post/5c6b6b126fb9a04a0c2f024f 1. 前言 我们经常在读到一些文章会遇到uri支持Ant风格 ,而且这个东西在Spring MVC和Spring Security中经常被提及。这到底是什...
小程序原生中使用async 和await 时会报错此时就是因为在.js中使用了async和await 但是小程序原生是不支持的解决方案1:npm init -y 快速创建一个packpage.json文件命令行执行 npm i regenerator-runtime安装regenerator-runtime打开小程序开发者工具,点击右上角的工具选项,点击构建npm,稍等几秒,小程序...
源:http://www.iteye.com/news/29113 这篇文章将介绍各种各样的网络资源(不包含必读的Java书籍),你可以借助这些资源进行在线学习。 学习Java最好的电子书(PDF) 如果你喜欢阅读,那么通过这些免费的Java电子书可以自学这门语言。大多数在线的电子书都是不断更新且完整的。覆盖了Java的大多数细节。 Oracle(Sun)官方教程:这是Addis...
一、简单页面1、CSS选择器样式优先级2、CSS实现三列布局(左右固定宽度,中间自适应)(1)CSS浮动第一个float:left,第二个float:right,第三个设置margin-left和margin-right(2)绝对定位法第一个定位到left,第二个定位到right,第三个设置margin-left和margin-right(3)flex布局.left{ width:200px; 或者 flex:0 0 200px;}.right{ width:200px;
最新的科技一般都是先有英文的,所以英语有多重要可想而知。我的英文很烂,一直想学,从来都是说起来容易,想起来简单,做起来最难。只能强迫自己多看些英语方面的技术网站,技术英语两不误。学习 Java 最好的电子书(PDF)喜欢阅读的可以通过这些免费的 Java 电子进行自学。大多数在线的电子书都是更新的,完整的。覆盖了 Java 的大多数细节。Official Java Tutorial by Orac
众所周知,通过PackageManager可以获取手机端已安装的apk文件的信息,具体代码如下:PackageManagerpackageManager=this.getPackageManager();ListpackageInfoList=packageManager.getInstalledPackages(0);/***查询手机内非系统应用*@paramcontext*@...
pip 国内的一些镜像阿里云 http://mirrors.aliyun.com/pypi/simple/中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/豆瓣(douban) http://pypi.douban.com/simple/清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/中国科学技术大学 http://pypi.mirrors.ustc.edu.cn/simple/修改源方法:临时使用:
Multi-Streams多流多流是企业级SSD的一个新特性,通过使用多流特性,可以显著提高SSD的垃圾回收效率,从而提高性能和延长寿命。在SSD的应用场景中,可能有多个不同的应用在对SSD进行写操作,包括热数据和冷数据,包括随机写数据和顺序写数据,包括大块写数据和小块写数据,如果把这些数据都混在同一个NAND块里面,显然不利于垃圾回收处理,一个很自然的想法是把这些数据进行分类。NVMe协议里面有两种方法可以对数据进行分类,其中一个是通过Dataset Management,另一个就是Multi-S
一、本文要点本文将介绍利用docker快速搭建开发环境,搭建Redis实例。系列文章完整目录docker 命令docker 安装redisdocker 常用命令docker 复制文件到宿主机docker 复制文件报错二、开发环境docker 18.09.7, build 2d0083dlinux 64位redis 4.0三、安装docker参考:https://blog.csdn.net/caiwen_5050/article/details/85245106四、安装Red
QT容器Java风格的使用以及基本操作(前后遍历toBack,hasPrevious,previous,toFront,hasNext,next,插入insert,删除remove,设值setValue,查找 findPrevious,findNext)