spring-framework源码第3弹------Spring IOC 容器的简单实现(学习tiny-spring)
声明:本代码来源于tiny-spring ,感谢原作者的源码
修改后的代码tiny-spring-copy
前言
学习Spring源码之前先学习下微缩版的Spring 框架—–tiny-spring 框架。闲话少说,先从IoC 容器开始。
IoC 的实现流程
- 读取配置文件,获取资源输入流
- 解析Bean,生成Bean的实例,
- 根据依赖注入Bean的实例
读取配置文件
Resource 接口,标识一个外部资源,通过getInputStream()
获取资源的输入流
public interface Resource {
InputStream getInputStream() throws IOException;
}
UrlResource 实现Resource接口
public class UrlResource implements Resource {
private final URL url;
public UrlResource(URL url) {
this.url = url;
}
@Override
public InputStream getInputStream() throws IOException{
URLConnection urlConnection = url.openConnection();
urlConnection.connect();
return urlConnection.getInputStream();
}
}
ResourceLoader 接口,加载资源,返回UrlResource 对象
public interface ResourceLoader {
/**
* @param location
* @return
*/
public Resource getResource(String location);
}
UrlResourceLoader类实现ResourceLoader接口
public class UrlResourceLoader implements ResourceLoader {
@Override
public Resource getResource(String location){
URL resource = this.getClass().getClassLoader().getResource(location);
return new UrlResource(resource);
}
}
解析配置文件,获取Bean的定义
- BeanDefinition 实体类,用于存放Bean的定义,包括Bean的内容和属性
public class BeanDefinition {
/**
*
*/
private Object bean;
/**
* Bean的类型
*/
private Class beanClass;
/**
* Bean的名称
*/
private String beanClassName;
/**
* 属性类,内部封装了一个List<PropertyValue>
*/
private PropertyValues propertyValues = new PropertyValues();
get和set方法省略
}
BeanDefinitionReader
解析BeanDefinition
接口,通过loadBeanDefinitions(String)
从一个地址加载类的定义
public interface BeanDefinitionReader {
/**
* 从配置中读取BeanDefinition
* @param location
* @throws Exception
*/
void loadBeanDefinitions(String location) throws Exception;
}
AbstractBeanDefinitionReader
实现BeanDefinitionReader
接口的抽象类,未具体实现loadBeanDefinitions(String)
,主要是规范了BeanDefinitionReader
的基本结构,
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader {
//用于保存String - beanDefinition 的键值对
private Map<String,BeanDefinition> registry;
//用于保存类加载器
private UrlResourceLoader resourceLoader;
protected AbstractBeanDefinitionReader(UrlResourceLoader resourceLoader) {
this.registry = new HashMap<String, BeanDefinition>();
this.resourceLoader = resourceLoader;
}
public Map<String, BeanDefinition> getRegistry() {
return registry;
}
public UrlResourceLoader getResourceLoader() {
return resourceLoader;
}
}
XmlBeanDefinitionReader
类,具体实现BeanDefinitionReader
接口,从配置文件中获取Bean的定义
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
public XmlBeanDefinitionReader(UrlResourceLoader resourceLoader) {
super(resourceLoader);
}
@Override
public void loadBeanDefinitions(String location) throws Exception {
InputStream inputStream = getResourceLoader().getResource(location).getInputStream();
doLoadBeanDefinitions(inputStream);
}
protected void doLoadBeanDefinitions(InputStream inputStream) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = factory.newDocumentBuilder();
Document doc = docBuilder.parse(inputStream);
// 解析bean
registerBeanDefinitions(doc);
inputStream.close();
}
/**
* 解析Bean
* @param doc
*/
public void registerBeanDefinitions(Document doc) {
Element root = doc.getDocumentElement();
parseBeanDefinitions(root);
}
/**
* 解析Bean
* @param root
*/
protected void parseBeanDefinitions(Element root) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
processBeanDefinition(ele);
}
}
}
/**
* 解析Bean中的id和class,以及其他属性
* @param ele
*/
protected void processBeanDefinition(Element ele) {
String name = ele.getAttribute("id");
String className = ele.getAttribute("class");
BeanDefinition beanDefinition = new BeanDefinition();
//保存属性
processProperty(ele, beanDefinition);
//保存类全限定名
beanDefinition.setBeanClassName(className);
//将获得的Bean的定义保存到map中
getRegistry().put(name, beanDefinition);
}
/**
* 解析Bean中的property属性
* @param ele
* @param beanDefinition
*/
private void processProperty(Element ele, BeanDefinition beanDefinition) {
NodeList propertyNode = ele.getElementsByTagName("property");
for (int i = 0; i < propertyNode.getLength(); i++) {
Node node = propertyNode.item(i);
if (node instanceof Element) {
Element propertyEle = (Element) node;
String name = propertyEle.getAttribute("name");
String value = propertyEle.getAttribute("value");
if (value != null && value.length() > 0) {
beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, value));
} else {
String ref = propertyEle.getAttribute("ref");
if (ref == null || ref.length() == 0) {
throw new IllegalArgumentException("Configuration problem: <property> element for property '"
+ name + "' must specify a ref or value");
}
BeanReference beanReference = new BeanReference(ref);
beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, beanReference));
}
}
}
}
}
注册生成Bean的实例 以及使用该实例
BeanFactory
类,标识一个IoC容器,通过getBean(String)
来获取Bean的实例。
public interface BeanFactory {
Object getBean(String name) throws Exception;
}
AbstractBeanFactory
类,BeanFactory
的一种抽象实现,规范了IoC容器的基本结构,但是把生成Bean的具体方式留给了子类来实现。
public abstract class AbstractBeanFactory implements BeanFactory {
private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
private final List<String> beanDefinitionNames = new ArrayList<String>();
private List<BeanPostProcessor> beanPostProcessors = new ArrayList<BeanPostProcessor>();
@Override
public Object getBean(String name) throws Exception {
BeanDefinition beanDefinition = beanDefinitionMap.get(name);
if (beanDefinition == null) {
throw new IllegalArgumentException("No bean named " + name + " is defined");
}
Object bean = beanDefinition.getBean();
//如果bean存在,则返回。否则调用doCreateBean方法装配一个Bean
if (bean == null) {
bean = doCreateBean(beanDefinition);
bean = initializeBean(bean, name);
beanDefinition.setBean(bean);
}
return bean;
}
/**
* 对Bean做初始化
* @param bean
* @param name
* @return
* @throws Exception
*/
protected Object initializeBean(Object bean, String name) throws Exception {
for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
bean = beanPostProcessor.postProcessBeforeInitialization(bean, name);
}
// TODO:call initialize method
for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
bean = beanPostProcessor.postProcessAfterInitialization(bean, name);
}
return bean;
}
protected Object createBeanInstance(BeanDefinition beanDefinition) throws Exception {
return beanDefinition.getBeanClass().newInstance();
}
public void registerBeanDefinition(String name, BeanDefinition beanDefinition) throws Exception {
beanDefinitionMap.put(name, beanDefinition);
beanDefinitionNames.add(name);
}
public void preInstantiateSingletons() throws Exception {
for (Iterator it = this.beanDefinitionNames.iterator(); it.hasNext();) {
String beanName = (String) it.next();
getBean(beanName);
}
}
/**
* 创建一个Bean的实例
* @param beanDefinition
* @return
* @throws Exception
*/
protected Object doCreateBean(BeanDefinition beanDefinition) throws Exception {
Object bean = createBeanInstance(beanDefinition);
beanDefinition.setBean(bean);
applyPropertyValues(bean, beanDefinition);
return bean;
}
protected void applyPropertyValues(Object bean, BeanDefinition beanDefinition) throws Exception {
}
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) throws Exception {
this.beanPostProcessors.add(beanPostProcessor);
}
public List getBeansForType(Class type) throws Exception {
List beans = new ArrayList<Object>();
for (String beanDefinitionName : beanDefinitionNames) {
if (type.isAssignableFrom(beanDefinitionMap.get(beanDefinitionName).getBeanClass())) {
beans.add(getBean(beanDefinitionName));
}
}
return beans;
}
}
AutowireCapableBeanFactory
可以实现自动装配的 BeanFactory
。在这个工厂中,实现了doCreateBean
方法,该方法分为三步:1. 通过BeanDefinition
中保存的类信息实例化一个对象;2.将对象保存在BeanDefinition
中,以备下次获取;3. 为其装配属性。在装配属性时,通过BeanDefinition
中维护的PropertyValues
集合类,把String-Value
键值对注入到Bean
的属性中去。如果Value
的类型是BeanReference
,则说明其是一个引用(对应于XML中的ref
),通过getBean
对其进行获取,然后注入到属性中。
public class AutowireCapableBeanFactory extends AbstractBeanFactory {
/**
* 将读取到的property值设置到Bean中
* @param bean
* @param mbd
* @throws Exception
*/
protected void applyPropertyValues(Object bean, BeanDefinition mbd) throws Exception {
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(this);
}
for (PropertyValue propertyValue : mbd.getPropertyValues().getPropertyValues()) {
Object value = propertyValue.getValue();
if (value instanceof BeanReference) {
BeanReference beanReference = (BeanReference) value;
value = getBean(beanReference.getName());
}
try {
Method declaredMethod = bean.getClass().getDeclaredMethod(
"set" + propertyValue.getName().substring(0, 1).toUpperCase()
+ propertyValue.getName().substring(1), value.getClass());
declaredMethod.setAccessible(true);
//反射方式设值
declaredMethod.invoke(bean, value);
} catch (NoSuchMethodException e) {
Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName());
declaredField.setAccessible(true);
declaredField.set(bean, value);
}
}
}
}
ApplicationContext
接口以及其实现类,主要是对Resource
,BeanFactory
,BeanDefinition
进行功能封装,解决根据地址获取IoC容器并使用的问题。
AbstractApplicationContext
类,ApplicationContext
的抽象实现,内部包含一个 BeanFactory
类
public abstract class AbstractApplicationContext implements ApplicationContext {
protected AbstractBeanFactory beanFactory;
public AbstractApplicationContext(AbstractBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public void refresh() throws Exception {
loadBeanDefinitions(beanFactory);
registerBeanPostProcessors(beanFactory);
onRefresh();
}
protected abstract void loadBeanDefinitions(AbstractBeanFactory beanFactory) throws Exception;
protected void registerBeanPostProcessors(AbstractBeanFactory beanFactory) throws Exception {
List beanPostProcessors = beanFactory.getBeansForType(BeanPostProcessor.class);
for (Object beanPostProcessor : beanPostProcessors) {
beanFactory.addBeanPostProcessor((BeanPostProcessor) beanPostProcessor);
}
}
protected void onRefresh() throws Exception{
beanFactory.preInstantiateSingletons();
}
@Override
public Object getBean(String name) throws Exception {
return beanFactory.getBean(name);
}
}
ClassPathXmlApplicationContext
类,从类路径加载资源的具体实现类
public class ClassPathXmlApplicationContext extends AbstractApplicationContext {
private String configLocation;
public ClassPathXmlApplicationContext(String configLocation) throws Exception {
this(configLocation, new AutowireCapableBeanFactory());
}
public ClassPathXmlApplicationContext(String configLocation, AbstractBeanFactory beanFactory) throws Exception {
super(beanFactory);
this.configLocation = configLocation;
refresh();
}
@Override
protected void loadBeanDefinitions(AbstractBeanFactory beanFactory) throws Exception {
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new UrlResourceLoader());
xmlBeanDefinitionReader.loadBeanDefinitions(configLocation);
for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) {
beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
}
}
tiny-spring 的ApplicaitonContext
使用流程是这样的:
ApplicaitonContext
完成了类定义的读取和加载,并注册到BeanFactory
中去。ApplicaitonContext
从BeanFactory
中寻找BeanPostProcessor
,注册到BeanFactory
维护的BeanPostProcessor
列表中去。ApplicaitonContext
以单例的模式,通过主动调用getBean
实例化、注入属性、然后初始化BeanFactory
中所有的Bean
。由于所有的BeanPostProcessor
都已经在第2步中完成实例化了,因此接下来实例化的是普通Bean
,因此普通Bean
的初始化过程可以正常执行。- 调用
getBean
时,委托给BeanFactory
,此时只是简单的返回每个Bean
单例,因为所有的Bean
实例在第三步都已经生成了。
参考
https://www.zybuluo.com/dugu9sword/note/382745#%E6%96%87%E4%BB%B6%E7%BB%93%E6%9E%84
相关文章
- Spring全家桶 源码 入门系列(二) --------AOP深度剖析
- Spring全家桶 源码 入门系列(一) --------容器与 bean
- spring支持几种bean的作用域?
- [转]Spring IOC 一——容器装配Bean的简单使用
- Spring注入bean的常用的六种方式
- Spring Cloud项目实战Spring Cloud视频教程 含源码
- 【Spring源码分析】Bean加载流程概览
- Spring Cloud系列Sentinel安装教程
- Spring源码之解析属性进行依赖注入(十)
- Spring源码之向容器注册Bean(六)
- Spring Cache 源码解析
- Spring Boot 2.x基础教程:使用MyBatis访问MySQL
- 《精通Spring MVC 4》——1.2 IntelliJ简介
- Spring boot(六)之Spring HATEOAS构建超媒体驱动的 RESTful Web 服务
- 【Spring常见错误】No qualifying bean of type
- spring boot + vue + element-ui全栈开发入门——基于Electron桌面应用开发
- 玩转spring boot——开篇
- 你的响应阻塞了没有?--Spring-WebFlux源码分析
- spring源码分析之spring-core-io
- 曹工说Spring Boot源码(16)-- Spring从xml文件里到底得到了什么(aop:config完整解析【上】)
- 曹工说Spring Boot源码(22)-- 你说我Spring Aop依赖AspectJ,我依赖它什么了
- 曹工说Spring Boot源码(4)-- 我是怎么自定义ApplicationContext,从json文件读取bean definition的?
- 曹工杂谈:为什么很少需要改Spring源码,因为扩展点太多了,说说Spring的后置处理器
- Spring Boot 2.X 装载 yaml 配置文件的键值对