相关文章:
Spring5 - 30个类手写实战 - 打卡第一天(V1版本)
Spring5 - 30个类手写实战 - 打卡第二天(IOC与DI)
Spring5 - 30个类手写实战 - 打卡第三天(MVC)
Spring5 - 30个类手写实战 - 打卡第四天(AOP)
1. IOC&DI
IOC(Inversion of Control) : 控制反转,所谓控制反转,就是把原先我们代码里面需要实现的对象创建、依赖的代码,反转给容器来帮忙实现。
DI(Dependency Injection):依赖注入,就是指对象是被动接受依赖类而不是自己主动去找,换句话说就是指对象不是从容器中查找它依赖的类,而是在容器实例化对象的时候主动将它依赖的类注入给他。
完成BeanDefinition的注册,放在beanDefinitionMap。
- ApplicationContext (入口)
ClassPathXmlApplicationContext
AnnotationConfigApplicationContext
WebApplicationContext
… - BeanDefinition
XmlBeanDefinition
… - BeanDefinitionReader
XmlBeanDefinitionReader
…
对象与对象的关系怎么表示?XML/YML/properties
描述对象关系的文件放在哪里?classpath/network/filesystem/servletContext/annotation
统一配置文件的标准?BeanDefinition
如何对不同的配置文件进行解析?策略模式
2.基于XML的IoC容器的初始化
IoC容器初始化大致分为三个步骤:
- 定位
定位配置文件和扫描相关的注解 - 加载
将配置信息载入到内存中 - 注册
根据载入的信息,将对象初始化到IOC容器
可详细划分为以下步骤:
IOC容器初始化的详细基本步骤:
- 初始化的入口在容器实现中的refresh()调用来完成
- 对Bean定义载入IOC容器使用的方法时loadBeanDefinition(),其中的大致流程如下:通过ResourceLoader来完成资源文件的定位,DefaultResourceLoader是默认的实现,同时上下文本身就给出了ResourceLoader的实现,可以从类路径,文件系统,URL等方式来定位资源位置。如果是XmlBeanFactory作为IOC容器,那么需要为它指定Bean定义的资源,也就是说Bean定义文件时通过抽象成Resource来被IOC容器处理的,容器通过BeanDefinitionReader来完成定义信息的解析和Bean信息的注册,往往使用的是XmlBeanDefinitionReader来解析Bean的XML定义文件-实际的处理过程是委托给BeanDefinitionParserDelegate来完成的,从而得到bean的定义信息,这些信息在Spring中使用BeanDefinition对象来表示,这个名字可以让我们想到loadBeanDefinition(),registerBeanDefinition()这些相关的方法。他们都是为处理BeanDefinition服务的,容器解析得到BeanDefinition以后,需要把它在IOC中注册,这由IOC实现BeanDefinitionRegistry接口来实现。注册过程就是在IOC容器内部维护一个HashMap来保存得到的BeanDefinition的过程。这个HashMap是IOC容器持有Bean信息的场所,以后对Bean的操作都是围绕这个HashMap来实现的。
- 然后我们就可以通过BeanFactory和ApplicationContext来享受到Spring IOC的服务了,在使用IOC容器的时候,我们注意到除了少量粘合代码,绝大多数以正确IOC风格编写的应用程序代码完全不用关心如何到达工厂,因为容器把这些对象与容器管理的其他对象关联在一起。基本的策略是把工厂放到已知的地方,最好是放在对预期使用的上下文有意义的地方,以及代码将实际需要访问工厂的地方。Spring本身提供了对申明式载入web应用程序用法得到采用程序上下文,并将其存储在ServletContext中的框架实现。
下面是容器初始化的简单时序图:
3. 基于Spring源码对之前代码调整
采用Spring的结构,LApplicationContext继承LBeanFactory,创建LDefaultListableBeanFactory也继承LBeanFactory,并将beanDefinitionMap以及getBean方法从LApplicationContext转移到LDefaultListableBeanFactory中。
LBeanFactory
package com.liulin.spring.framework.core;
/**
* Create by DbL on 2020/5/4 0004
*/
public interface LBeanFactory {
public Object getBean(String beanName);
public Object getBean(Class beanClass);
}
LDefaultListableBeanFactory
package com.liulin.spring.framework.beans.support;
import com.liulin.spring.framework.beans.config.LBeanDefinition;
import com.liulin.spring.framework.core.LBeanFactory;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Create by DbL on 2020/5/4 0004
*/
public class LDefaultListableBeanFactory implements LBeanFactory {
public Map<String, LBeanDefinition> beanDefinitionMap = new HashMap<String, LBeanDefinition>();
@Override
public Object getBean(String beanName) {
return null;
}
@Override
public Object getBean(Class beanClass) {
return null;
}
public void doRegistBeanDefinition(List<LBeanDefinition> beanDefinitions) throws Exception {
for (LBeanDefinition beanDefinition : beanDefinitions) {
if (this.beanDefinitionMap.containsKey(beanDefinition.getFactoryBeanName())) {
throw new Exception("The " + beanDefinition.getFactoryBeanName() + " is Exists");
}
beanDefinitionMap.put(beanDefinition.getFactoryBeanName(), beanDefinition);
beanDefinitionMap.put(beanDefinition.getBeanClassName(), beanDefinition);
}
}
}