title: Spring 框架源码解读1
date: 2020/04/14
前言
为什么要阅读 Spring 源码?
作为一个 Java 后台开发,在工作中肯定离不开 Spring,但是却对 Spring 中的实现原理只有大致的了解,没有深入的理解,所以想要通过这部分专栏带大家一起“深入”的了解 Spring 源码。
Spring 简介
Spring 是一个 IoC(Inversion of Control,控制反转)框架。
IoC 是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递(注入)给它。 —— 维基百科
为什么需要 IoC ?
Java 是面向对象语言,在 Java 中万物皆对象,我们的程序就是由各种对象组成的,当多个类之间关系变成下面这样复杂的时候,维护起来心里可能会有1万只“草泥马”。
我们知道,在计算机领域,没有什么问题是加一层解决不了的,所以为了解决这个问题,我们引入 IoC 框架,让框架来维护类与类之间那错综复杂的关系,使我们解脱出来。
这个时候我们发现,我们类之间的关系都由 IoC 框架负责维护类,同时将类注入到需要的类中。
类的使用者只负责使用,而不负责维护。
本专栏内容
1、我会带着大家从0开始自己写一个 IoC 框架,功能与 Spring 大体相同。
2、当实现完一部分功能之后,我就会带着大家一起看看 Spring 0.9 中是怎样实现的
3、然后再分析与 5.0 版本的区别
本节内容 & 思考题
今天会带大家动手搓一个 BeanFactory。
大家想一下在 Spring 中 BeanFactory 的作用是什么,它采用了什么设计模式?
手写 BeanFactory
1、创建 Maven 项目,引入 hutool 工具类
cn.hutool
hutool-all
4.6.1
2、书写 BeanDefinition
BeanDefinition 定义了 bean 的信息,例如:它的名字、全类名、单例还是原型等
/**
* bean 的属性
*
* @author yujx
* @date 2020/04/14 14:57
*/
public interface BeanDefinition {
/**
* 名称
*/
String getName();
/**
* 设置名称
*/
void setName(String name);
/**
* 类名称
*/
String getClassName();
/**
* 设置类名称
*/
void setClassName(String className);
ScopeEnum getScope();
void setScope(ScopeEnum scope);
enum ScopeEnum {
SINGLETON,
PROTOTYPE
}
}
/**
* 默认实现(Spring 中有两个实现 RootBD 和 ChildBD 其中 ChildBD 我们基本用不到)
*
* @author yujx
* @date 2020/04/14 15:05
*/
public class DefaultBeanDefinition implements BeanDefinition {
// 名称
private String name;
// 全类名
private String className;
// 生命周期
private ScopeEnum scope = ScopeEnum.SINGLETON;
/**
* 名称
*/
@Override
public String getName() {
return name;
}
/**
* 设置名称
*/
@Override
public void setName(String name) {
this.name = name;
}
/**
* 类名称
*/
@Override
public String getClassName() {
return className;
}
/**
* 设置类名称
*/
@Override
public void setClassName(String className) {
this.className = className;
}
@Override
public ScopeEnum getScope() {
return scope;
}
@Override
public void setScope(ScopeEnum scope) {
this.scope = scope;
}
}
3、定义 BeanFactory 接口
BeanFactory 是生产 bean 的工厂
AbstractBeanFactory 实现了 BeanFactory 中的所有方法,并维护了单例的 Map,并提供一个抽象方法getBeanDefinition(beanName)
在 Spring 中 ListableBeanFactory 接口继承了它并扩展了它,提供了遍历 bd 相关的方法
ListableBeanFactoryImpl 继承了 AbstractBeanFactory 并实现了 ListableBeanFactory 接口,实现了他们的抽象方法,它的主要功能是维护 bd 的 Map。
JsonBeanFactory 是 Spring 中 XmlBF 的代替品,因为我不想解析恶心人的 xml,它负责读取 json 文件,向 bf 中注册 bd 信息。
/** * 生产 bean 的工厂 * * @author yujx * @date 2020/04/14 14:37 */ public interface BeanFactory { /** * 根据名称获取对应的 bean(工厂方法模式) */ Object getBean(String name); /** * 根据名称和它的类型获取对应的 bean */
T getBean(String name, Class requiredType); } /** * 负责维护单例对象(在 Spring 源码中该类还负责维护 parent 的bf,应该是为了 Spring MVC) * * @author yujx * @date 2020/04/14 19:14 */ public abstract class AbstractBeanFactory implements BeanFactory { // key:名字 value:单例对象 private final Map sharedInstanceCache = new ConcurrentHashMap<>(); /** * 根据名称获取对应的 bean (工厂方法模式) */ @Override public Object getBean(String name) { if (sharedInstanceCache.containsKey(name)) { return sharedInstanceCache.get(name); } // 获取 bean 的属性信息 BeanDefinition beanDefinition = this.getBeanDefinition(name); if (ObjectUtil.isNull(beanDefinition)) { throw new RuntimeException("获取的bean不存在!"); } Object bean = this.createBean(beanDefinition); // 如果该对象是单例的,则加入到缓存中。 if (beanDefinition.getScope().equals(BeanDefinition.ScopeEnum.SINGLETON)) { sharedInstanceCache.put(name, bean); } return bean; } // 根据 bd 创建对象 private Object createBean(BeanDefinition beanDefinition) { return ReflectUtil.newInstance(beanDefinition.getClassName()); } /** * 根据名称和它的类型获取对应的 bean */ public T getBean(String name, Class requiredType) { Object bean = getBean(name); if (bean.getClass().equals(requiredType)) { return (T) bean; } throw new RuntimeException("获取bean的类型错误!"); } /** * 根据名称获取 bd (子类实现) * * @param beanName * @return */ protected abstract BeanDefinition getBeanDefinition(String beanName); } /** * 扩展了bf,可以根据类型返回容器中所有的 bean * * BeanFactory的扩展将由可以枚举其所有bean实例的bean工厂来实现,而不是按照客户的要求按名称一一尝试。 * * @author yujx * @date 2020/04/14 14:48 */ public interface ListableBeanFactory extends BeanFactory { /** * 根据类型获取容器中所有该类型的对象 */
Map getBeansOfType(Class type); } /** * ListableBeanFactory 工厂的实现,并负责维护 bd 信息 * * @author yujx * @date 2020/04/14 14:56 */ public class ListableBeanFactoryImpl extends AbstractBeanFactory implements ListableBeanFactory { // key:名字 value:bean 的信息 private final Map beanDefinitionMap = new ConcurrentHashMap<>(); // key:字节码类型 value:名字数组(Spring 源码中是通过 beanDefinitionMap 遍历出来的,我们这里为了方便) private final Map , Set > allBeanNamesByType = new ConcurrentHashMap<>(64); /** * 注册 bean 的信息 */ protected final void registerBeanDefinition(String name, BeanDefinition beanDefinition) { beanDefinitionMap.put(name, beanDefinition); // 将相同类型的beanName放入 allBeanNamesByType 中 String className = beanDefinition.getClassName(); Class type = this.getType(className); Set beanNameSet = allBeanNamesByType.getOrDefault(type, new HashSet<>(1)); beanNameSet.add(beanDefinition.getName()); allBeanNamesByType.put(type, beanNameSet); } // 根据全类名获取类型 private Class getType(String className) { try { return Thread.currentThread().getContextClassLoader().loadClass(className); } catch (ClassNotFoundException e) { e.printStackTrace(); throw new RuntimeException(e); } } /** * 根据类型获取容器中所有该类型的对象 */ @Override public Map getBeansOfType(Class type) { Set beanNameSet = allBeanNamesByType.get(type); if (ObjectUtil.isNull(beanNameSet)) { return new HashMap<>(0); } Map map = new HashMap<>(beanNameSet.size()); for (String beanName : beanNameSet) { map.put(beanName, this.getBean(beanName, type)); } return map; } /** * 根据名称获取 bd (子类实现) * * @param beanName * @return */ @Override protected BeanDefinition getBeanDefinition(String beanName) { return beanDefinitionMap.get(beanName); } } /** * 因为我不想解析xml,所以用json来代替 *
* 负责从不同类型文件中读取配置并注册进 bd 的 Map 中 * * @author yujx * @date 2020/04/14 15:26 */ public class JsonBeanFactoryImpl extends ListableBeanFactoryImpl { public JsonBeanFactoryImpl(String fileName) { JSONArray jsonArray = JSONUtil.readJSONArray(new File(fileName), StandardCharsets.UTF_8); this.loadBeanDefinitions(jsonArray); } private void loadBeanDefinitions(JSONArray jsonArray) { List
beanDefinitionList = jsonArray.toList(DefaultBeanDefinition.class); for (DefaultBeanDefinition bd : beanDefinitionList) { super.registerBeanDefinition(bd.getName(), bd); } } }
4、测试
public class Apple {
private String name = "红富士";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Apple{" +
"name='" + name + '\'' +
'}';
}
}
public class TestJsonBF {
public static void main(String[] args) {
ListableBeanFactory bf = new JsonBeanFactory("/Users/x5456/IdeaProjects/Summer/src/test/resources/apple.json");
Apple apple = bf.getBean("apple", Apple.class);
System.out.println(apple);
Map beansOfType = bf.getBeansOfType(Apple.class);
System.out.println(beansOfType);
}
}
apple.json
[
{"name":"apple","className":"cn.x5456.summer.Apple"},
{"name":"apple2","className":"cn.x5456.summer.Apple"},
{"name":"apple3","className":"cn.x5456.summer.Apple"}
]
其实我觉得 BeanFactory、AbstractBeanFactory、ListableBeanFactoryImpl、JsonBeanFactoryImpl 他们几个符合单一职责,他们虽然是父子关系,但他们几个彼此之间都在做不同的事情。
脑海中有一个念头告诉我,这应该是不好的,应该可以用设计模式优化,但是我想不起来。
Spring 0.9 中的实现
BeanFactory 和我的写法基本相同,相较于多了别名相关的东西。
AbstractBeanFactory 中的方法也基本相同,多了一个父BF。
ListableBeanFactoryImpl 也和我的写法相同
XmlBeanFactory 也基本相同
Spring 5.0 中区别
各个类的职责依然没变,只是方法增多了很多,依赖注入部分增加了对注解的支持(AbstractAutowireCapableBeanFactory),虽然依赖注入我还没说,XmlBF 也已经被标注成废弃,现在主要使用的是 ApplicationContext 了,ApplicationContext 部分我们下次再说。
思考题答案
BeanFactory 是用来获取我们交给 Spring 容器管理的对象的。
它采用了工厂方法模式。