Spring源码------手写体验IOC与DI
目录
1、前言
本篇博客并非是对Spring源码的深入研究。而是对上一篇博客《Spring源码------手写体验MVC》结构的优化。过程中主要是体验Spring IOC和DI的初始化过程。那么这篇博客涉及到的知识点大致有以下几点:
- 如何自定义注解,如何通过反射机制去赋予注解强大的功能(说白了,就是体验在反射机制下,注解功能是多么的强大)
- Spring Ioc容器的实现原理
- Spring DI 注解注入
- Java反射机制
- Java I/O流(加载配置文件,读取配置文件信息)
2、Spring IOC和DI原理流程
Spring IOC的基本流程:
- 读取配置文件
- 解析配置文件,并封装成BeanDefinition
- 把BeanDefinition对应的实例放到容器进行缓存
Spring DI的基本流程:
- 循环读取BeanDefinition的缓存信息
- 调用getBean()方法创建对象实例
- 将创建好的对象实例包装为BeanWrapper对象
- 将BeanWrapper对象缓存到IOC容器中
- 循环IOC容器执行来进行注入
大致流图:
3、核心代码
代码结构图:
核心上下文applicationContext 代码:
**
* @description: 自定义上下文
* @author: zps
* @create: 2020-05-08 15:06
**/
public class ZPSApplicationContext {
private ZPSBeanDefinitionReader reader ;
//保存BeanDefinition信息
private Map<String , ZPSBeanDefinition> beanDefinitionMap = new HashMap<String , ZPSBeanDefinition>();
private Map<String, ZPSBeanWrapper> factoryBeanInstanceCache = new HashMap<String, ZPSBeanWrapper>();
private Map<String,Object> factoryBeanObjectCache = new HashMap<String, Object>();
public ZPSApplicationContext(String... contextConfigLocation) {
//加载配置文件
reader = new ZPSBeanDefinitionReader(contextConfigLocation);
//解析配置文件,封装成BeanDefinition
List<ZPSBeanDefinition> beanDefinitions = reader.loadBeanDefinitions();
//把BeanDefinition缓存起来
try {
doRegistBeanDefinition(beanDefinitions);
} catch (Exception e) {
e.printStackTrace();
}
//依赖注入,这里默认没有延迟加载
doAutowired();
}
private void doAutowired() {
//调用getBean()
//这一步,所有的Bean并没有真正的实例化,还只是配置阶段
for(Map.Entry<String , ZPSBeanDefinition> beanDefinitionEntry : this.beanDefinitionMap.entrySet()){
//根据类名进行初始化
getBean(beanDefinitionEntry.getKey());
}
}
//把BeanDefinition缓存起来
private void doRegistBeanDefinition(List<ZPSBeanDefinition> beanDefinitions) throws Exception {
for (ZPSBeanDefinition 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);
}
}
//Bean的实例化,DI是从而这个方法开始的
public Object getBean(String beanName){
//1、先拿到BeanDefinition配置信息
ZPSBeanDefinition beanDefinition = this.beanDefinitionMap.get(beanName);
//2、反射实例化newInstance();
Object instance = instantiateBean(beanName,beanDefinition);
//3、封装成一个叫做BeanWrapper
ZPSBeanWrapper beanWrapper = new ZPSBeanWrapper(instance);
//4、保存到IoC容器
factoryBeanInstanceCache.put(beanName,beanWrapper);
//5、执行依赖注入
populateBean(beanName,beanDefinition,beanWrapper);
return beanWrapper.getWrapperInstance();
}
//执行依赖注入
private void populateBean(String beanName, ZPSBeanDefinition beanDefinition, ZPSBeanWrapper zpsBeanWrapper) {
Object instance = zpsBeanWrapper.getWrapperInstance();
Class<?> clazz = zpsBeanWrapper.getWrappedClass();
//在Spring中@Component
if(!(clazz.isAnnotationPresent(ZPSController.class) || clazz.isAnnotationPresent(ZPSService.class))){
return;
}
//把所有的包括private/protected/default/public 修饰字段都取出来
for (Field field : clazz.getDeclaredFields()) {
if(!field.isAnnotationPresent(ZPSAutowired.class)){ continue; }
ZPSAutowired autowired = field.getAnnotation(ZPSAutowired.class);
//如果用户没有自定义的beanName,就默认根据类型注入
String autowiredBeanName = autowired.value().trim();
if("".equals(autowiredBeanName)){
//field.getType().getName() 获取字段的类型
autowiredBeanName = field.getType().getName();
}
//暴力访问
field.setAccessible(true);
try {
if(this.factoryBeanInstanceCache.get(autowiredBeanName) == null){
continue;
}
//ioc.get(beanName) 相当于通过接口的全名拿到接口的实现的实例
field.set(instance,this.factoryBeanInstanceCache.get(autowiredBeanName).getWrapperInstance());
} catch (IllegalAccessException e) {
e.printStackTrace();
continue;
}
}
}
private Object instantiateBean(String beanName, ZPSBeanDefinition beanDefinition) {
String className = beanDefinition.getBeanClassName();
Object instance = null;
try {
if(this.factoryBeanObjectCache.containsKey(beanName)){
instance = this.factoryBeanObjectCache.get(beanName);
}else {
Class<?> clazz = Class.forName(className);
//2、默认的类名首字母小写
instance = clazz.newInstance();
this.factoryBeanObjectCache.put(beanName, instance);
}
}catch (Exception e){
e.printStackTrace();
}
return instance;
}
public Object getBean(Class<?> clazz){
return getBean(clazz.getName());
}
public int getBeanDefinitionCounts() {
return this.beanDefinitionMap.size();
}
public String[] gteBeanDefinitionNames() {
return this.beanDefinitionMap.keySet().toArray(new String[this.beanDefinitionMap.size()]);
}
}
对应上图的BeanDefinition:
**
* @description: 读取配置文件工具类
* @author: zps
* @create: 2020-05-08 15:18
**/
public class ZPSBeanDefinitionReader {
Properties properties = new Properties();
//保存扫描的bean的类名信息
private List<String> regitryBeanClasses = new ArrayList<String>();
public ZPSBeanDefinitionReader(String... configLocations){
//读取配置文件信息
doConfig(configLocations[0]);
//对文件进行扫描,筛选出需要的类文件
doScanner(properties.getProperty("scanPackage"));
}
//对文件进行扫描
private void doScanner(String scanPackage) {
//jar 、 war 、zip 、rar
URL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\.","/"));
File classPath = new File(url.getFile());
//当成是一个ClassPath文件夹
for (File file : classPath.listFiles()) {
if(file.isDirectory()){
doScanner(scanPackage + "." + file.getName());
}else {
if(!file.getName().endsWith(".class")){continue;}
//全类名 = 包名.类名
String className = (scanPackage + "." + file.getName().replace(".class", ""));
//Class.forName(className);
regitryBeanClasses.add(className);
}
}
}
//加载配置文件
private void doConfig(String configLocation) {
InputStream is = this.getClass().getClassLoader().getResourceAsStream(configLocation.replaceAll("classpath:",""));
try {
properties.load(is);
} catch (IOException e) {
e.printStackTrace();
}finally {
if(null != is){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public List<ZPSBeanDefinition> loadBeanDefinitions(){
List<ZPSBeanDefinition> result = new ArrayList<ZPSBeanDefinition>();
try {
for (String className : regitryBeanClasses) {
Class<?> beanClass = Class.forName(className);
//保存类对应的ClassName(全类名)
//还有beanName
//1、默认是类名首字母小写
result.add(doCreateBeanDefinition(toLowerFirstCase(beanClass.getSimpleName()), beanClass.getName()));
//2、自定义
//3、接口注入
for (Class<?> i : beanClass.getInterfaces()) {
result.add(doCreateBeanDefinition(i.getName(),beanClass.getName()));
}
}
}catch (Exception e){
e.printStackTrace();
}
return result;
}
private ZPSBeanDefinition doCreateBeanDefinition(String beanName, String beanClassName) {
ZPSBeanDefinition beanDefinition = new ZPSBeanDefinition();
beanDefinition.setFactoryBeanName(beanName);
beanDefinition.setBeanClassName(beanClassName);
return beanDefinition;
}
private String toLowerFirstCase(String simpleName) {
char [] chars = simpleName.toCharArray();
chars[0] += 32;
return String.valueOf(chars);
}
}
对应上图的BeanDefinition(该类主要是封装从配置文件中读取的类信息):
**
* @description: 封装类的信息
* @author: zps
* @create: 2020-05-08 15:23
**/
public class ZPSBeanDefinition {
private String factoryBeanName; //简单类名
private String beanClassName; //全类名
public String getFactoryBeanName() {
return factoryBeanName;
}
public void setFactoryBeanName(String factoryBeanName) {
this.factoryBeanName = factoryBeanName;
}
public String getBeanClassName() {
return beanClassName;
}
public void setBeanClassName(String beanClassName) {
this.beanClassName = beanClassName;
}
}
对应上图的BeanWrapper :
/**
* @description: bean的包装类
* @author: zps
* @create: 2020-05-08 17:39
**/
public class ZPSBeanWrapper {
private Object wrapperInstance;
private Class<?> wrappedClass;
public ZPSBeanWrapper(Object instance) {
this.wrapperInstance = instance;
this.wrappedClass = instance.getClass();
}
public Object getWrapperInstance() {
return wrapperInstance;
}
public Class<?> getWrappedClass() {
return wrappedClass;
}
}
运行截图:
4、总结
对Spring Ioc 和DI 大致工作流程的描述:
Spring IOC的基本流程:
- 读取配置文件
- 解析配置文件,并封装成BeanDefinition
- 把BeanDefinition对应的实例放到容器进行缓存
Spring DI的基本流程:
- 循环读取BeanDefinition的缓存信息
- 调用getBean()方法创建对象实例
- 将创建好的对象实例包装为BeanWrapper对象
- 将BeanWrapper对象缓存到IOC容器中
- 循环IOC容器执行来进行注入