工作五六年了,我是第一次被自己蠢到,连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对象,这个类为一个支持方法接口的类
@FunctionalInterfacepublic 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、设置属性BapplyPropertyValues(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、设置属性AapplyPropertyValues(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@75b84c92mydemo.jdk.proxy.RealSubject@75b84c92
这两个是一个东西。
哎!真是人有失手,马有失蹄!
后面突然又纠结起来了!
如果一直共用一个对象的话,那
getEarlyBeanReference(beanName, mbd, bean)
岂不是很多余?
毕竟就算先设置B的属性a,不对a进行代理先也可以啊,反正引用的是最同一个对象,在最后初始化A的时候再给A设置代理也是可以的啊,为啥还要多此一举?看来不仔细研读源码是不知道了!
