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 工具类
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.6.1</version>
</dependency>
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> T getBean(String name, Class<T> 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<String, Object> 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> T getBean(String name, Class<T> 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
* <p>
* BeanFactory的扩展将由可以枚举其所有bean实例的bean工厂来实现,而不是按照客户的要求按名称一一尝试。
*
* @author yujx
* @date 2020/04/14 14:48
*/
public interface ListableBeanFactory extends BeanFactory {
/**
* 根据类型获取容器中所有该类型的对象
*/
<T> Map<String, T> getBeansOfType(Class<T> type);
}
/**
* ListableBeanFactory 工厂的实现,并负责维护 bd 信息
*
* @author yujx
* @date 2020/04/14 14:56
*/
public class ListableBeanFactoryImpl extends AbstractBeanFactory implements ListableBeanFactory {
// key:名字 value:bean 的信息
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
// key:字节码类型 value:名字数组(Spring 源码中是通过 beanDefinitionMap 遍历出来的,我们这里为了方便)
private final Map<Class<?>, Set<String>> 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<String> 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 <T> Map<String, T> getBeansOfType(Class<T> type) {
Set<String> beanNameSet = allBeanNamesByType.get(type);
if (ObjectUtil.isNull(beanNameSet)) {
return new HashMap<>(0);
}
Map<String, T> 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来代替
* <p>
* 负责从不同类型文件中读取配置并注册进 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<DefaultBeanDefinition> 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<String, Apple> 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 容器管理的对象的。
它采用了工厂方法模式。