工作五六年了,我是第一次被自己蠢到,连java最基础最基本对象引用都搞混了,可能是最近没有怎么写代码练习的原因,真是罪过罪过。
事情是这样的,在看spring的源码,开始看到对象初始化了。
//1、实例化
instanceWrapper = createBeanInstance(beanName, mbd, args);
//2、获取对象
Object bean = instanceWrapper.getWrappedInstance();
//3、加入singletonObjects(三级缓存中),顺便弄个回调方法。
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
//4、将引用指向暴露到一个对象中
Object exposedObject = bean;
try {
//5、给对象的属性赋值
populateBean(beanName, mbd, instanceWrapper);
//6、初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
我们知道,在第3步骤将我们的bean放入到了三级缓存(singletonObjects)中,其中key为beanName,value为一个ObjectFactory对象,这个类为一个支持方法接口的类
@FunctionalInterface
public interface ObjectFactory<T> {
T getObject() throws BeansException;
}
也就是在什么地方如果调用了这个对象的getObject方法那么就会执行
getEarlyBeanReference(beanName, mbd, bean)
然后我发现,如果有循环依赖,也就是在第五步骤给对象赋值初始属性的时候,有循环依赖比如此时是在初始化A对象,但是有如下循环依赖
public class A{
private B b;
}
public class B{
private A a
}
那么接下来的流程就是会去设置B属性
//1、设置A的属性
populateBean(beanName, mbd, instanceWrapper);
//2、设置属性B
applyPropertyValues(beanName, mbd, bw, pvs)
//3、解析属性B,如果需要的话
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
//4、初始化属性B对象
bean = this.beanFactory.getBean(resolvedName);
上面兜兜转转又回到了初始化B的方法,也会走一开始A的流程,然后也会到达
//1、设置B的属性
populateBean(beanName, mbd, instanceWrapper);
//2、设置属性A
applyPropertyValues(beanName, mbd, bw, pvs)
//3、解析属性A,如果需要的话
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
//4、初始化属性A对象
bean = this.beanFactory.getBean(resolvedName);
但是在此时的第4步骤,会走到逻辑
Object sharedInstance = getSingleton(beanName);
里面对应的代码如下
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
在前面我们知道,我们已经把属性A放到三级缓存(singletonObjects)中,其中key为beanName,value为一个ObjectFactory对象,此时上面的方法调用
singletonObject = singletonFactory.getObject();
也就是会调用
getEarlyBeanReference(beanName, mbd, bean)
那上面这段逻辑干了啥呢?
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
好吧,原来是这样,因为前面要设置B的属性A了,所以一定要有一个比较完整一点的A,也就是比如我们有Aop的话,可以在这里做增强,然后返回代理对象A回去。
问题来了?
这里对A进行了增强,那刚开始的A,也就是一开始实例化后的A
Object exposedObject = bean;
exposedObject这个怎么办,两个对象都不一样了,后面还是用这个啊!
然后这个蠢问题,这个最基础最基本的蠢问题,让我想了一天,我竟然忘记了Java的基础。忘记了上面的exposedObject不是对象,是引用,它指向的内存中的对象被代理了后,其实自己就开始指向代理,所以是一样的啊!
然后为了这个蠢问题,我还去证明了一下,如下代码
public class DynamicProxyDemonstration
{
public static void main(String[] args)
{
//代理的真实对象
Subject realSubject = new RealSubject();
InvocationHandler handler = new InvocationHandlerImpl(realSubject);
ClassLoader loader = realSubject.getClass().getClassLoader();
Class[] interfaces = realSubject.getClass().getInterfaces();
//获得代理后的对象
Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);
System.out.println(subject);
System.out.println(realSubject);
}
}
运行,输出结果
mydemo.jdk.proxy.RealSubject@75b84c92
mydemo.jdk.proxy.RealSubject@75b84c92
这两个是一个东西。
哎!真是人有失手,马有失蹄!
后面突然又纠结起来了!
如果一直共用一个对象的话,那
getEarlyBeanReference(beanName, mbd, bean)
岂不是很多余?
毕竟就算先设置B的属性a,不对a进行代理先也可以啊,反正引用的是最同一个对象,在最后初始化A的时候再给A设置代理也是可以的啊,为啥还要多此一举?看来不仔细研读源码是不知道了!