手写Spring Ioc 循环依赖底层源码剖析
前言
Spring Ioc 是一个非常重要的框架,它的核心是依赖注入(DI)和控制反转(IOC)。在使用 Spring Ioc 的过程中,我们经常会遇到循环依赖的问题。本文将介绍手写 Spring Ioc 循环依赖的底层源码剖析。
什么是循环依赖
循环依赖是指两个或多个 Bean 之间相互依赖,形成了一个环路。例如,Bean A 依赖于 Bean B,而 Bean B 又依赖于 Bean A,这就形成了一个循环依赖。
Spring Ioc 循环依赖的解决方案
Spring Ioc 提供了两种解决循环依赖的方案:
- 提前暴露半成品 Bean
- 使用三级缓存
提前暴露半成品 Bean
提前暴露半成品 Bean 是指在创建 Bean 的过程中,如果发现循环依赖,就将半成品 Bean 提前暴露出来,以便其他 Bean 可以使用。等到所有 Bean 都创建完成后,再将半成品 Bean 完成创建。
使用三级缓存
使用三级缓存是指在创建 Bean 的过程中,如果发现循环依赖,就将正在创建的 Bean 放入三级缓存中。等到所有 Bean 都创建完成后,再从三级缓存中取出 Bean,完成创建。
手写 Spring Ioc 循环依赖的底层源码剖析
下面我们来手写一个简单的 Spring Ioc 容器,实现循环依赖的解决方案。
BeanDefinition
首先,我们需要定义一个 BeanDefinition 类,用于保存 Bean 的信息,包括 Bean 的名称、类型、属性等。
public class BeanDefinition {private String name;private Class<?> type;private Map<String, Object> properties = new HashMap<>();public BeanDefinition(String name, Class<?> type) {this.name = name;this.type = type;}public String getName() {return name;}public Class<?> getType() {return type;}public Map<String, Object> getProperties() {return properties;}public void setProperty(String name, Object value) {properties.put(name, value);}
}
BeanFactory
接下来,我们定义一个 BeanFactory 接口,用于获取 BeanDefinition 和 Bean。
public interface BeanFactory {BeanDefinition getBeanDefinition(String name);Object getBean(String name);
}
AbstractBeanFactory
然后,我们定义一个 AbstractBeanFactory 抽象类,实现 BeanFactory 接口的 getBean 方法,并提供一个 createBean 方法,用于创建 Bean。
public abstract class AbstractBeanFactory implements BeanFactory {private Map<String, BeanDefinition> beanDefinitions = new HashMap<>();private Map<String, Object> singletonBeans = new HashMap<>();private Map<String, Object> earlySingletonBeans = new HashMap<>();private Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>();@Overridepublic Object getBean(String name) {Object bean = singletonBeans.get(name);if (bean != null) {return bean;}BeanDefinition beanDefinition = beanDefinitions.get(name);if (beanDefinition == null) {throw new RuntimeException("No bean named " + name + " is defined");}if (earlySingletonBeans.containsKey(name)) {bean = earlySingletonBeans.get(name);if (bean != null) {return bean;}}ObjectFactory<?> singletonFactory = singletonFactories.get(name);if (singletonFactory != null) {bean = singletonFactory.getObject();earlySingletonBeans.put(name, bean);singletonFactories.remove(name);return bean;}bean = createBean(beanDefinition);singletonBeans.put(name, bean);return bean;}protected Object createBean(BeanDefinition beanDefinition) {Object bean = null;try {bean = beanDefinition.getType().newInstance();} catch (InstantiationException | IllegalAccessException e) {e.printStackTrace();}for (Map.Entry<String, Object> entry : beanDefinition.getProperties().entrySet()) {try {Field field = bean.getClass().getDeclaredField(entry.getKey());field.setAccessible(true);field.set(bean, entry.getValue());} catch (NoSuchFieldException | IllegalAccessException e) {e.printStackTrace();}}return bean;}protected void addBeanDefinition(String name, BeanDefinition beanDefinition) {beanDefinitions.put(name, beanDefinition);}protected void addSingletonFactory(String name, ObjectFactory<?> singletonFactory) {singletonFactories.put(name, singletonFactory);}
}
DefaultBeanFactory
最后,我们定义一个 DefaultBeanFactory 类,继承 AbstractBeanFactory 抽象类,实现 BeanFactory 接口的 getBeanDefinition 方法,并提供一个 registerBeanDefinition 方法, 用于注册 BeanDefinition。
public class DefaultBeanFactory extends AbstractBeanFactory {@Overridepublic BeanDefinition getBeanDefinition(String name) {return super.beanDefinitions.get(name);}public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {super.addBeanDefinition(name, beanDefinition);}
}
测试
现在,我们来测试一下我们手写的 Spring Ioc 容器是否能够解决循环依赖的问题。
首先,我们定义两个类 A 和 B,它们相互依赖。
public class A {private B b;public void setB(B b) {this.b = b;}
}public class B {private A a;public void setA(A a) {this.a = a;}
}
然后,我们在容器中注册这两个类的 BeanDefinition。
DefaultBeanFactory beanFactory = new DefaultBeanFactory();BeanDefinition aBeanDefinition = new BeanDefinition("a", A.class);
aBeanDefinition.setProperty("b", new ObjectFactory<B>() {@Overridepublic B getObject() {return (B) beanFactory.getBean("b");}
});
beanFactory.registerBeanDefinition("a", aBeanDefinition);BeanDefinition bBeanDefinition = new BeanDefinition("b", B.class);
bBeanDefinition.setProperty("a", new ObjectFactory<A>() {@Overridepublic A getObject() {return (A) beanFactory.getBean("a");}
});
beanFactory.registerBeanDefinition("b", bBeanDefinition);
最后,我们从容器中获取 A 和 B 的实例,并验证它们是否相互依赖。
A a = (A) beanFactory.getBean("a");
B b = (B) beanFactory.getBean("b");assert a != null;
assert b != null;
assert a.getB() == b;
assert b.getA() == a;
测试通过,我们手写的 Spring Ioc 容器能够解决循环依赖的问题。
总结
本文介绍了手写 Spring Ioc 循环依赖的底层源码剖析。通过实现一个简单的 Spring Ioc 容器,我们了解了 Spring Ioc 解决循环依赖的两种方案,并掌握了手写 Spring Ioc 容器的方法。