一、前言
本来是打算背八股来学习Spring的,但是发现很多内容如果不亲自敲一遍根本记不住,同时也没法学习到Spring框架源码中的各种精妙设计,尤其是设计模式的运用,于是打算新开一个项目,通过一步一步的增加功能,最后实现一个简易Spring。这一节先从IOC容器讲起,一步一步的将代码复杂化,一步一步贴近真正的spring框架。
另外也不要想着去默写源码之类的,我把02版本默写了一次,其实就已经有点吃不消了,到后面还会扩展至几十个类,默写肯定是不现实的。这里着重去学架构思维即可。
二、01-最简Bean容器版本
这里我们先给出Bean容器最初的样子,很朴实,就是一个基于Map存储的容器,根据键拿值(对象)。选择Map作为底层容器是因为Map的特性,利用哈希可以通过键查询快速定位值。
java
public class BeanDefinition {
private Object bean;
public BeanDefinition(Object bean) {
this.bean = bean;
}
public Object getBean() {
return bean;
}
}
java
public class BeanFactory {
private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
public Object getBean(String name) {
return beanDefinitionMap.get(name).getBean();
}
public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {
beanDefinitionMap.put(name, beanDefinition);
}
}
可以看到这个版本也是基本实现了spring功能的,但是也可以看到部分问题,比如创建对象的步骤是在框架外部进行的,正常我们应该传入一个Class,然后由框架内部帮忙创建Bean对象(反射),所以这都是后面可以进行改进的地方。
java
@Test
public void test_BeanFactory(){
// 1.初始化 BeanFactory
BeanFactory beanFactory = new BeanFactory();
// 2.注册 bean
BeanDefinition beanDefinition = new BeanDefinition(new UserService());
beanFactory.registerBeanDefinition("userService", beanDefinition);
// 3.获取 bean
UserService userService = (UserService) beanFactory.getBean("userService");
userService.queryUserInfo();
}
三、02-IOC核心版本
基于上一个版本,我们将对最后提到的问题进行优化,因此这次我先给测试类,看看这次我们实现的效果能做到什么样:
java
@Test
public void test_BeanFactory() throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
// 1.初始化 BeanFactory
// 注意这里用的是 DefaultListableBeanFactory(那个真正有 registerBeanDefinition 的实现类),
// 不是 BeanFactory 接口 ------ 接口上并没有注册方法。
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 2.注册 bean:这里传的是 UserService.class,不是 new UserService()
BeanDefinition beanDefinition = new BeanDefinition(UserService.class);
beanFactory.registerBeanDefinition("userService", beanDefinition);
// 3.第一次获取 bean:缓存里没有,走 createBean 反射实例化
UserService userService = (UserService) beanFactory.getBean("userService");
userService.queryUserInfo();
// 4.第二次获取 bean from Singleton:这次必须直接命中单例缓存,不能再 new 一个
UserService userService_singleton = (UserService) beanFactory.getBean("userService");
userService_singleton.queryUserInfo();
// 额外验证:两次拿到的是不是同一个对象(这一章真正的考点)
System.out.println("两次获取是否为同一个对象:" + (userService == userService_singleton));
}
这里先给出整体架构,可以看到相较于前面的最简版本,这里多出了很多类。但是也不用太害怕,这些类大多数是为了解耦而存在的,所以比起背源码,把这几个核心类的功能记住才是真的。
java
small-spring-step-02
└── src
├── main
│ └── java
│ └── cn.bugstack.springframework.beans
│ ├── factory
│ │ ├── config
│ │ │ ├── BeanDefinition.java
│ │ │ └── SingletonBeanRegistry.java
│ │ ├── support
│ │ │ ├── AbstractAutowireCapableBeanFactory.java
│ │ │ ├── AbstractBeanFactory.java
│ │ │ ├── BeanDefinitionRegistry.java
│ │ │ ├── DefaultListableBeanFactory.java
│ │ │ └── DefaultSingletonBeanRegistry.java
│ │ └── BeanFactory.java
│ └── BeansException.java
└── test
└── java
└── cn.bugstack.springframework.test
├── bean
│ └── UserService.java
└── ApiTest.java
依赖关系:

1.BeanDefinition
从这里开始,BeanDefinition就不是前面最简版的定义了,前面的它就是一个装载Bean对象的类,把Bean对象作为属性存放。而这个版本,由于我们需求变了,这个类中的属性也就变成了装载Class对象了。
所以这个类顾名思义,就是Bean的定义类。
这里可能会有疑惑,为什么要保存 Class 对象,而不是直接保存 Bean 实例?
因为 Spring 的设计并不是在注册 Bean 时就把所有 Bean 都创建出来,而是先保存 Bean 的定义信息,后续由容器根据这些定义完成 Bean 的创建、管理以及缓存。
在真实 Spring 中,BeanDefinition 后续还会承载更多 Bean 的定义信息;而在当前这个手写 Spring 的第三章里,为了简化实现,暂时只保存 Bean 对应的
Class类型。至于我们平时使用的
@Component、@Service、@Controller等注解,Spring 会在应用启动阶段 进行组件扫描,识别这些注解标记的类,并进一步将它们转换、注册为 BeanDefinition。这里的扫描过程属于运行时的容器启动过程,而不是编译时。这一部分会在后面的章节继续实现。
java
public class BeanDefinition {
private Class beanClass;
public BeanDefinition(Class beanClass) {
this.beanClass = beanClass;
}
// ...get/set
}
2. 单例注册接口定义和实现
从前面我们可以看出Bean的创建流程:首先先存在BeanDefinition中,然后创建为Bean对象。
我们先来看创建为Bean对象后,这个对象应该存哪里,怎么存?
于是我们专门用了一个类来实现这个功能:DefaultSingletonBeanRegistry(默认单例Bean注册器),这个地方和最简版的BeanFactory干了一样的事情:
java
public interface SingletonBeanRegistry {
Object getSingleton(String beanName);
}
java
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
private Map<String, Object> singletonObjects = new HashMap<>();
@Override
public Object getSingleton(String beanName) {
return singletonObjects.get(beanName);
}
protected void addSingleton(String beanName, Object singletonObject) {
singletonObjects.put(beanName, singletonObject);
}
}
3.抽象类定义模板方法
AbstractBeanFactory 模板抽象类是用来规定Bean的获取流程(getBean)骨架的,它提供了两个抽象方法,由子类实现具体功能。学了大营销应该就会很熟悉这个设计模式,当时在策略领域时,我们就用了模板抽象类来定义了抽奖的规则过滤骨架(前置中置)。
同时这个抽象类继承了默认单例注册器类,因此是可以直接控制bean对象的获取和存储的。
在流程骨架中,我们先会尝试去获取单例容器中的Bean,如果没有才会去创建;而创建过程还额外需要BeanDefiniton,因此获取BeanDefinition和createBean我们都交由子类去实现。
最终目的还是为了解耦。
java
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory {
@Override
public Object getBean(String name) throws BeansException {
Object bean = getSingleton(name);
if (bean != null) {
return bean;
}
BeanDefinition beanDefinition = getBeanDefinition(name);
return createBean(name, beanDefinition);
}
protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;
protected abstract Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException;
}
(1)createBean
单独交由子类 AbstractAutowireCapableBeanFactory 实现:
java
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {
@Override
protected Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException {
Object bean = null;
try {
bean = beanDefinition.getBeanClass().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new BeansException("Instantiation of bean failed", e);
}
addSingleton(beanName, bean);
return bean;
}
}
(2)getBeanDefinition
这里面用于存储BeanDefinition,然后实现getBeanDefinition方法。
DefaultListableBeanFactory是最核心的类,为啥呢?
因为他是处于继承链的顶端,也就是可以通过这个类间接调用前面的所有功能。
因此在我们测试类中,是直接通过这一个类就能调用前面定义和实现的所有方法。
java
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry {
private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
beanDefinitionMap.put(beanName, beanDefinition);
}
@Override
public BeanDefinition getBeanDefinition(String beanName) throws BeansException {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if (beanDefinition == null) throw new BeansException("No bean named '" + beanName + "' is defined");
return beanDefinition;
}
}
测试类中所有的方法都是由这个 DefaultListableBeanFactory 对象提供的:

然而这个版本还有缺陷,你可以注意到,我们当前是不支持有参构造的,我们的UserService一直都是无参构造出来的。
java
public class UserService {
public void queryUserInfo(){
System.out.println("查询用户信息");
}
}
一旦增加一些成员变量,要用到有参构造,运行时就会报错:
java
public class UserService {
private String name;
public UserService(String name) {
this.name = name;
}
public void queryUserInfo(){
System.out.println("查询用户信息");
}
}

这个问题我们留到下个版本解决。
四、03-Cglib优化版本
这个版本就是为了优化上一节最后留的问题,对于这个优化,我的顺序和xfg略有不同,我倾向于从问题点出发:
根据上面的报错,首先就找到的createBean这个方法,所以一定是在实例化Bean的时候出了问题,
java
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {
@Override
protected Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException {
Object bean = null;
try {
bean = beanDefinition.getBeanClass().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new BeansException("Instantiation of bean failed", e);
}
addSingleton(beanName, bean);
return bean;
}
}
问题的根源就出自这里:这里默认是进行无参构造,如果只有有参构造是不行的,这里要通过构造器反射再进行实例化。
java
bean = beanDefinition.getBeanClass().newInstance();
而对于这里的构造,其实是有两种方式实现的:一种是cglib,一种是JDK。因此这属于一种策略选择,我们使用策略模式进行代码的实现。
1.重载getBean
首先要重载getBean方法,我们需要提供额外的参数用于构造:
java
public interface BeanFactory {
Object getBean(String name) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
}
2.策略模式
然后提供接口,策略模式。
java
public interface InstantiationStrategy {
Object instantiate(BeanDefinition beanDefinition, String beanName, Constructor ctor, Object[] args) throws BeansException;
}
JDK实现:
java
public class SimpleInstantiationStrategy implements InstantiationStrategy {
@Override
public Object instantiate(BeanDefinition beanDefinition, String beanName, Constructor ctor, Object[] args) throws BeansException {
Class clazz = beanDefinition.getBeanClass();
try {
if (ctor != null) {//如果有有参构造器,就传参进来
return clazz.getDeclaredConstructor(ctor.getParameterTypes()).newInstance(args);
} else {//如果没有有参构造器,就默认无参
return clazz.getDeclaredConstructor().newInstance();
}
} catch (Exception e) {
throw new BeansException("Failed to instantiate [" + clazz.getName() + "]", e);
}
}
}
cglib实现:
java
public class CglibSubclassingInstantiationStrategy implements InstantiationStrategy {
@Override
public Object instantiate(BeanDefinition beanDefinition, String beanName, Constructor ctor, Object[] args) throws BeansException {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(beanDefinition.getBeanClass());
enhancer.setCallback(new NoOp() {
@Override
public int hashCode() {
return super.hashCode();
}
});
if (null == ctor) return enhancer.create();
return enhancer.create(ctor.getParameterTypes(), args);
}
}
3.createBean提供策略选择
java
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {
private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
@Override
protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException {
Object bean = null;
try {
bean = createBeanInstance(beanDefinition, beanName, args);
} catch (Exception e) {
throw new BeansException("Instantiation of bean failed", e);
}
addSingleton(beanName, bean);
return bean;
}
protected Object createBeanInstance(BeanDefinition beanDefinition, String beanName, Object[] args) {
Constructor constructorToUse = null;
Class<?> beanClass = beanDefinition.getBeanClass();
Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
for (Constructor ctor : declaredConstructors) {
if (null != args && ctor.getParameterTypes().length == args.length) {
constructorToUse = ctor;
break;
}
}
return getInstantiationStrategy().instantiate(beanDefinition, beanName, constructorToUse, args);
}
public InstantiationStrategy getInstantiationStrategy() {
return instantiationStrategy;
}
public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {
this.instantiationStrategy = instantiationStrategy;
}
}
4.测试
java
public class UserService {
private String name;
public UserService(String name) {
this.name = name;
}
public void queryUserInfo() {
System.out.println("查询用户信息:" + name);
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("");
sb.append("").append(name);
return sb.toString();
}
}
java
public class ApiTest {
@Test
public void test_BeanFactory() {
// 1.初始化 BeanFactory
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 2. 注入bean
BeanDefinition beanDefinition = new BeanDefinition(UserService.class);
beanFactory.registerBeanDefinition("userService", beanDefinition);
// 3.获取bean
UserService userService = (UserService) beanFactory.getBean("userService", "小傅哥");
userService.queryUserInfo();
}
}