注意,本文不涉及对Spring源码的解析
在本文中,我们将通过代码来实现一个简单的Spring容器
通过不断完善自定义的Spring容器,我们将逐步认识到Spring的三级缓存各自的作用
1. 无任何依赖的Bean
先来个最简单的,假设Spring容器管理的都是无任何依赖的Bean:
java
class A { }
class B { }
Spring容器的实现如下:
java
public class Spring {
/**
* beanMap用于存放所有已经创建的Bean;其中,key为beanName,value为Bean本身
*/
private Map<String, Object> beanMap = new HashMap<>();
/**
* beanDefinitionMap用于模拟xml文件的解析结果;其中key为beanName,value为Bean的类型
*/
private Map<String, Class> beanDefinitionMap = new HashMap<>();
{
beanDefinitionMap.put("a", A.class);
beanDefinitionMap.put("b", B.class);
}
/**
* 初始化Spring容器,根据beanDefinitionMap来生成相应的Bean
*/
private Spring() throws Exception {
// 遍历所有的BeanDefinition,并获取相应的Bean
// 这里调用getBean()方法并不是为了获取Bean,而是为了触发Bean的创建
for (Map.Entry<String, Class> entry : beanDefinitionMap.entrySet()) {
getBean(entry.getKey(), entry.getValue());
}
}
/**
* 创建Bean的核心方法
*/
private Object getBean(String beanName, Class beanClass) throws Exception {
// 如果已经创建过了,则直接返回已创建的
Object bean = beanMap.get(beanName);
if (bean != null) {
return bean;
}
// 直接通过反射创建Bean实例
bean = beanClass.newInstance();
System.out.println(bean + " created!");
// 将该Bean放到beanMap中并返回
beanMap.put(beanName, bean);
return bean;
}
/**
* 测试程序,打印出容器中所有的Bean
*/
public static void main(String[] args) throws Exception {
new Spring().beanMap.forEach((beanName, bean) -> System.out.println(beanName + ": " + bean));
}
}
结果如下:
text
A@4f2410ac created!
B@722c41f4 created!
a: A@4f2410ac
b: B@722c41f4
2. 无循环依赖的Bean
复杂一点,假设A类中有个B b;
字段:
java
class A { B b; }
class B { }
显然,此时需要对a对象进行依赖注入,实现如下:
java
public class Spring {
private Map<String, Object> beanMap = new HashMap<>();
private Map<String, Class> beanDefinitionMap = new HashMap<>();
{
beanDefinitionMap.put("a", A.class);
beanDefinitionMap.put("b", B.class);
}
private Spring() throws Exception {
for (Map.Entry<String, Class> entry : beanDefinitionMap.entrySet()) {
getBean(entry.getKey(), entry.getValue());
}
}
/**
* 对原来的getBean()方法进行改进
*/
private Object getBean(String beanName, Class beanClass) throws Exception {
Object bean = beanMap.get(beanName);
if (bean != null) {
return bean;
}
bean = beanClass.newInstance();
System.out.println(bean + " created!");
// 依赖注入;为了方便,我们直接将字段名称当作beanName来查找对应的Bean
for (Field field : beanClass.getDeclaredFields()) {
String fieldName = field.getName();
Object dependency = getBean(fieldName, beanDefinitionMap.get(fieldName));
System.out.println(bean + ": " + fieldName + "=" + dependency);
field.set(bean, dependency);
}
beanMap.put(beanName, bean);
return bean;
}
public static void main(String[] args) throws Exception {
new Spring().beanMap.forEach((beanName, bean) -> System.out.println(beanName + ": " + bean));
}
}
结果如下:
text
A@4f2410ac created!
B@5b80350b created!
A@4f2410ac: b=B@5b80350b
a: A@4f2410ac
b: B@5b80350b
3. 循环依赖的Bean
再复杂一点,假设B类中也有个A a;
字段,此时出现循环依赖:
java
class A { B b; }
class B { A a; }
这时候,上述实现的Spring容器就会不断地创建a和b对象,最终栈溢出,原因:
- 首先,创建a对象,并对其进行依赖注入(注意此时a对象并未存放到
beanMap
中) - 对a进行依赖注入时,发现b对象不存在,因此创建b对象,并对其进行依赖注入
- 对b进行依赖注入时,发现a对象不存在(因为之前创建的a对象没保存到
beanMap
中),因此容器又去创建a对象,导致死循环
解决方法是,在创建对象之后、进行依赖注入之前就把对象存到beanMap
:
java
public class Spring {
private Map<String, Object> beanMap = new HashMap<>();
private Map<String, Class> beanDefinitionMap = new HashMap<>();
{
beanDefinitionMap.put("a", A.class);
beanDefinitionMap.put("b", B.class);
}
private Spring() throws Exception {
for (Map.Entry<String, Class> entry : beanDefinitionMap.entrySet()) {
getBean(entry.getKey(), entry.getValue());
}
}
/**
* 对原来的getBean()方法进行改进
*/
private Object getBean(String beanName, Class beanClass) throws Exception {
Object bean = beanMap.get(beanName);
if (bean != null) {
return bean;
}
bean = beanClass.newInstance();
System.out.println(bean + " created!");
// 立刻将Bean放入beanMap中
beanMap.put(beanName, bean);
// 对该Bean进行依赖注入,然后返回该Bean
for (Field field : beanClass.getDeclaredFields()) {
String fieldName = field.getName();
Object dependency = getBean(fieldName, beanDefinitionMap.get(fieldName));
System.out.println(bean + ": " + fieldName + "=" + dependency);
field.set(bean, dependency);
}
return bean;
}
public static void main(String[] args) throws Exception {
new Spring().beanMap.forEach((beanName, bean) -> System.out.println(beanName + ": " + bean));
}
}
结果如下:
text
A@4f2410ac created!
B@5b80350b created!
B@5b80350b: a=A@4f2410ac
A@4f2410ac: b=B@5b80350b
a: A@4f2410ac
b: B@5b80350b
4. 循环依赖 + AOP
我们只使用了一级缓存(即beanMap
)就解决了循环依赖的问题;但这还不够,因为我们没有考虑到AOP的情况
假设我们需要对a进行AOP增强,那么b中注入的a实际上应该是a的代理而不是a本身,这样的话上面的实现就有问题了
java
/**
* 为了方便,我们规定实现了本接口的类就代表该类需要进行AOP增强
*/
interface Proxyable { }
class A implements Proxyable { B b; }
class B { Proxyable a; }
上述的实现中,我们是直接将a本身放到了一级缓存中,导致注入b中的就是a本身,这就不符合要求了
因此,在实例化对象之后,需要判断该对象是否需要AOP;如果需要,则应创建它的代理对象并将代理对象放入beanMap
中:
java
public class Spring {
private Map<String, Object> beanMap = new HashMap<>();
private Map<String, Class> beanDefinitionMap = new HashMap<>();
{
beanDefinitionMap.put("a", A.class);
beanDefinitionMap.put("b", B.class);
}
private Spring() throws Exception {
for (Map.Entry<String, Class> entry : beanDefinitionMap.entrySet()) {
getBean(entry.getKey(), entry.getValue());
}
}
/**
* 对原来的getBean()方法进行改进
*/
private Object getBean(String beanName, Class beanClass) throws Exception {
Object bean = beanMap.get(beanName);
if (bean != null) {
return bean;
}
// 创建原始对象
Object rowBean = beanClass.newInstance();
System.out.println(rowBean + " created!");
// 如果该对象有AOP增强,则创建该对象的代理对象
// 注意proxyOrSelf才是真正需要暴露出去的对象,因此将其存到beanMap中
Object proxyOrSelf = proxyIfNecessary(rowBean);
beanMap.put(beanName, proxyOrSelf);
// 对原始对象进行依赖注入
for (Field field : beanClass.getDeclaredFields()) {
String fieldName = field.getName();
Object dependency = getBean(fieldName, beanDefinitionMap.get(fieldName));
System.out.println(rowBean + ": " + fieldName + "=" + dependency);
field.set(rowBean, dependency);
}
// 注意proxyOrSelf才是真正要返回(暴露)的对象
return proxyOrSelf;
}
/**
* 模拟AOP增强
*/
private Object proxyIfNecessary(Object bean) {
if (!(bean instanceof Proxyable)) {
return bean;
}
Object beanProxy = Proxy.newProxyInstance(
bean.getClass().getClassLoader(),
bean.getClass().getInterfaces(),
(proxy, method, args) -> {
if (method.getName().equals("toString")) {
return "Proxy(delegate=" + bean.toString() + ")";
}
return method.invoke(bean, args);
}
);
System.out.println(beanProxy + " created!");
return beanProxy;
}
public static void main(String[] args) throws Exception {
new Spring().beanMap.forEach((beanName, bean) -> System.out.println(beanName + ": " + bean));
}
}
结果如下:
text
A@4f2410ac created!
Proxy(delegate=A@4f2410ac) created!
B@16b3fc9e created!
B@16b3fc9e: a=Proxy(delegate=A@4f2410ac)
A@4f2410ac: b=B@16b3fc9e
a: Proxy(delegate=A@4f2410ac)
b: B@16b3fc9e
5. 三级缓存
上述的代码还存在一个问题,原因在于:
- Spring的AOP是通过
BeanPostProcessor
来实现的,而BeanPostProcessor
在正常情况下应该等到Bean初始化时再执行 - 我们的代码为了解决AOP和循环依赖的问题,在Bean刚刚实例化后就立刻生成其代理对象,也就是提前执行了
BeanPostProcessor
- 因此,我们的做法是破坏了Spring的规范的
想象这样一种情形:a需要进行AOP增强,但是a依赖的Bean并没有反过来依赖a
- 那么a的代理对象完全可以等到a初始化完成后再创建
- 但是,我们的代码中,一上来就创建了a的代理对象,这显然是不对的
我们希望尽量让代理对象在原始对象初始化完成后再创建,只有在万不得已的情况下才提前创建代理对象,因此引入ProxyFactory
:
java
/**
* ProxyFactory主要用于获取Bean的代理对象
*/
interface ProxyFactory {
/**
* 封装代理对象的创建逻辑;注意:
* 1. 在原始对象没有AOP增强的情况下,该方法返回的是原始对象本身
* 2. 代理对象只有在调用get()方法时才会创建
*
* 假设a需要进行AOP增强,并且a依赖了b:
* 1. 那么,在实例化a后,我们可以将a的代理对象的创建逻辑封装到ProxyFactory中,并将该ProxyFactory缓存起来
* 2. 如果b依赖了a,即出现了循环依赖,那么在对b进行依赖注入时,可以调用a的ProxyFactory的get()方法提前获取到a代理对象
* 3. 如果b没有依赖a,那么a的ProxyFactory的get()方法没有被调用,这时候就可以在a初始化完成后再创建a的代理对象了
*/
Object get();
}
具体的实现逻辑:
java
public class Spring {
private Map<String, Object> beanMap = new HashMap<>();
private Map<String, Class> beanDefinitionMap = new HashMap<>();
{
beanDefinitionMap.put("a", A.class);
beanDefinitionMap.put("b", B.class);
}
/**
* beanFactoryMap中,key为beanName,value为Bean的代理对象工厂
*/
private Map<String, ProxyFactory> proxyFactoryMap = new HashMap<>();
private Spring() throws Exception {
for (Map.Entry<String, Class> entry : beanDefinitionMap.entrySet()) {
getBean(entry.getKey(), entry.getValue());
}
}
/**
* 对原来的getBean()方法进行改进
*/
private Object getBean(String beanName, Class beanClass) throws Exception {
Object bean = beanMap.get(beanName);
if (bean != null) {
return bean;
}
// 判断是否有代理对象工厂,如果有,说明该Bean之前已经创建过了,只是没有初始化完成
// 因此,如果有代理对象工厂,说明出现了循环依赖,此时需要通过工厂提前获取代理对象并返回
// 注意,工厂使用过后要删掉,避免重复创建代理对象从而破坏单例;同时还要把得到的代理对象放到一级缓存中
ProxyFactory proxyFactory = proxyFactoryMap.remove(beanName);
if (proxyFactory != null) {
Object proxy = proxyFactory.get();
beanMap.put(beanName, proxy);
return proxy;
}
// 创建原始对象
Object rowBean = beanClass.newInstance();
System.out.println(rowBean + " created!");
// 将代理对象的创建逻辑封装到ProxyFactory中
// 这样的话,如果该Bean有AOP增强,且其它Bean依赖了该Bean,那么其它Bean可以通过该工厂获得该Bean的代理
proxyFactoryMap.put(beanName, () -> proxyIfNecessary(rowBean));
// 对原始对象进行依赖注入
for (Field field : beanClass.getDeclaredFields()) {
String fieldName = field.getName();
Object dependency = getBean(fieldName, beanDefinitionMap.get(fieldName));
System.out.println(rowBean + ": " + fieldName + "=" + dependency);
field.set(rowBean, dependency);
}
// 判断该Bean对应的代理对象工厂是否存在(如果存在,则顺便删除掉)
// 如果存在,说明代理对象没有提前创建,即没有出现循环依赖,此时创建该Bean的代理对象(如果有必要的话)并返回
// 如果不存在,说明其它Bean通过代理工厂提前创建了本Bean的代理对象;此时需要返回代理对象(该代理对象肯定在一级缓存中)
proxyFactory = proxyFactoryMap.remove(beanName);
// 如果没有循环依赖,则创建代理对象,并将代理对象放入一级缓存,然后返回该代理对象
if (proxyFactory != null) {
Object proxyOrSelf = proxyFactory.get();
beanMap.put(beanName, proxyOrSelf);
return proxyOrSelf;
}
// 否则,该Bean一定已经在一级缓存中了,因此返回一级缓存中的Bean
return beanMap.get(beanName);
}
private Object proxyIfNecessary(Object bean) {
if (!(bean instanceof Proxyable)) {
return bean;
}
Object beanProxy = Proxy.newProxyInstance(
bean.getClass().getClassLoader(),
bean.getClass().getInterfaces(),
(proxy, method, args) -> {
if (method.getName().equals("toString")) {
return "Proxy(delegate=" + bean.toString() + ")";
}
return method.invoke(bean, args);
}
);
System.out.println(beanProxy + " created!");
return beanProxy;
}
public static void main(String[] args) throws Exception {
new Spring().beanMap.forEach((beanName, bean) -> System.out.println(beanName + ": " + bean));
}
}
结果如下:
text
class A implements Proxyable { B b; }
class B { Proxyable a; }
A@4f2410ac created!
B@782830e created!
Proxy(delegate=A@4f2410ac) created!
B@782830e: a=Proxy(delegate=A@4f2410ac)
A@4f2410ac: b=B@782830e
a: Proxy(delegate=A@4f2410ac)
b: B@782830e
--------------------------------------------------
class A implements Proxyable { B b; }
class B { }
A@4f2410ac created!
B@782830e created!
A@4f2410ac: b=B@782830e
Proxy(delegate=A@4f2410ac) created!
a: Proxy(delegate=A@4f2410ac)
b: B@782830e
6. 二级缓存
我们只通过一级缓存和三级缓存就解决了循环依赖和AOP的问题,但这么做还是存在一些问题:
- 问题在于我们直接将成品和半成品都存放到了一级缓存中
- 也就是说,如果用户从一级缓存中获取Bean,有可能获取到的是半成品,就可能引起空指针异常
- 因此,还需要再加一个缓存,专门用来存放半成品,而一级缓存则只存放成品
java
public class Spring {
private Map<String, Object> beanMap = new HashMap<>();
private Map<String, Class> beanDefinitionMap = new HashMap<>();
{
beanDefinitionMap.put("a", A.class);
beanDefinitionMap.put("b", B.class);
}
private Map<String, ProxyFactory> proxyFactoryMap = new HashMap<>();
/**
* proxyMap中,key为beanName,value为Bean的代理对象(当然也有可能是原始的Bean对象),并且该对象未初始化完成
*/
private Map<String, Object> proxyMap = new HashMap<>();
private Spring() throws Exception {
for (Map.Entry<String, Class> entry : beanDefinitionMap.entrySet()) {
getBean(entry.getKey(), entry.getValue());
}
}
/**
* 对原来的getBean()方法进行改进
*/
private Object getBean(String beanName, Class beanClass) throws Exception {
Object bean = beanMap.get(beanName);
if (bean != null) {
return bean;
}
// 如果二级缓存中有代理对象,说明该Bean的代理对象已经提前创建了,此时将代理对象返回
// 注意,此时不需要将代理对象从二级缓存移到一级缓存,因为此时的代理对象还未初始化完成
Object proxy = proxyMap.get(beanName);
if (proxy != null) {
return proxy;
}
// 如果有代理对象工厂,则提前生成代理对象,将代理对象存放到二级缓存中并返回
ProxyFactory proxyFactory = proxyFactoryMap.remove(beanName);
if (proxyFactory != null) {
proxyMap.put(beanName, proxy = proxyFactory.get());
return proxy;
}
// 创建原始对象
Object rowBean = beanClass.newInstance();
System.out.println(rowBean + " created!");
// 将代理对象的创建逻辑封装到ProxyFactory中
// 这样的话,如果该Bean有AOP增强,且其它Bean依赖了该Bean,那么其它Bean可以通过该工厂获得该Bean的代理
proxyFactoryMap.put(beanName, () -> proxyIfNecessary(rowBean));
// 对原始对象进行依赖注入
for (Field field : beanClass.getDeclaredFields()) {
String fieldName = field.getName();
Object dependency = getBean(fieldName, beanDefinitionMap.get(fieldName));
System.out.println(rowBean + ": " + fieldName + "=" + dependency);
field.set(rowBean, dependency);
}
// 判断该Bean对应的代理对象工厂是否存在(如果存在,则顺便删除掉)
// 如果存在,说明代理对象没有提前创建,即没有出现循环依赖,此时创建该Bean的代理对象(如果有必要的话)并返回
// 如果不存在,说明其它Bean通过代理工厂提前创建了本Bean的代理对象;此时需要返回代理对象(该代理对象肯定在二级缓存中)
proxyFactory = proxyFactoryMap.remove(beanName);
// 如果没有循环依赖,则创建代理对象,并将代理对象放入一级缓存,然后返回该代理对象
if (proxyFactory != null) {
beanMap.put(beanName, proxy = proxyFactory.get());
return proxy;
}
// 否则,将代理对象从二级缓存转移到一级缓存并返回
beanMap.put(beanName, proxy = proxyMap.remove(beanName));
return proxy;
}
private Object proxyIfNecessary(Object bean) {
if (!(bean instanceof Proxyable)) {
return bean;
}
Object beanProxy = Proxy.newProxyInstance(
bean.getClass().getClassLoader(),
bean.getClass().getInterfaces(),
(proxy, method, args) -> {
if (method.getName().equals("toString")) {
return "Proxy(delegate=" + bean.toString() + ")";
}
return method.invoke(bean, args);
}
);
System.out.println(beanProxy + " created!");
return beanProxy;
}
public static void main(String[] args) throws Exception {
new Spring().beanMap.forEach((beanName, bean) -> System.out.println(beanName + ": " + bean));
}
}
结果如下:
text
class A implements Proxyable { B b; }
class B { Proxyable a; }
A@4f2410ac created!
B@782830e created!
Proxy(delegate=A@4f2410ac) created!
B@782830e: a=Proxy(delegate=A@4f2410ac)
A@4f2410ac: b=B@782830e
a: Proxy(delegate=A@4f2410ac)
b: B@782830e
--------------------------------------------------
class A implements Proxyable { B b; }
class B { }
A@4f2410ac created!
B@782830e created!
A@4f2410ac: b=B@782830e
Proxy(delegate=A@4f2410ac) created!
a: Proxy(delegate=A@4f2410ac)
b: B@782830e
7. 最终测试
我们用一个更加复杂的例子来测试上述代码:
java
class A implements Proxyable { B b; Proxyable d; }
class B { Proxyable a; }
class C implements Proxyable { Proxyable a; B b; Proxyable d; }
class D implements Proxyable { Proxyable d; }
java
public class Spring {
private Map<String, Class> beanDefinitionMap = new HashMap<>();
{
beanDefinitionMap.put("a", A.class);
beanDefinitionMap.put("b", B.class);
beanDefinitionMap.put("c", C.class);
beanDefinitionMap.put("d", D.class);
}
// 省略其它代码
}
执行结果:
text
A@4f2410ac created! // 创建a对象
B@782830e created! // 对a对象进行依赖注入时,发现需要b对象,因此创建b对象
Proxy(delegate=A@4f2410ac) created! // 对b对象进行依赖注入时,发现需要a对象,因此提前暴露a的代理对象
B@782830e: a=Proxy(delegate=A@4f2410ac) // b对象依赖注入成功
A@4f2410ac: b=B@782830e // a对象的b字段注入成功
D@3b22cdd0 created! // 对a对象进行依赖注入时,发现需要d对象,因此创建d对象
Proxy(delegate=D@3b22cdd0) created! // 对d对象进行依赖注入时,发现需要d对象,因此提前暴露d的代理对象
D@3b22cdd0: d=Proxy(delegate=D@3b22cdd0) // d对象底层注入的是d的代理对象
A@4f2410ac: d=Proxy(delegate=D@3b22cdd0) // a对象的d字段注入成功
C@4d591d15 created! // 按照顺序,这里应该创建b对象,但b对象之前已经创建了,因此轮到c对象了
C@4d591d15: a=Proxy(delegate=A@4f2410ac) // 由于一级缓存中已经有a对象了,因此直接注入给c对象
C@4d591d15: b=B@782830e // 由于一级缓存中已经有b对象了,因此直接注入给c对象
C@4d591d15: d=Proxy(delegate=D@3b22cdd0) // 由于一级缓存中已经有d对象了,因此直接注入给c对象
Proxy(delegate=C@4d591d15) created! // c对象依赖注入完成,创建其代理对象
a: Proxy(delegate=A@4f2410ac)
b: B@782830e
c: Proxy(delegate=C@4d591d15)
d: Proxy(delegate=D@3b22cdd0)