读过Spring源码的同志请留步,问个问题。

mrvoce 发布于 2012/02/04 12:26
阅读 1K+
收藏 1

AbstractBeanFactory这个类的doGetBean是进行bean依赖的注入并返回填充好的bean实例,请问一下

 

final RootBeanDefinition mbd =getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
//Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
 if (dependsOn != null) {
	for (int i = 0; i < dependsOn.length; i++) {
	String dependsOnBean = dependsOn[i];
        //这里有个回调函数
	getBean(dependsOnBean);	
        //注册依赖注入bean
        registerDependentBean(dependsOnBean, beanName);
	}
}

 这个是依赖bean的注入部分代码,回调函数一直看不懂为什么这样做,而且最近想设计一个IOC但是由于出现一个问题让我很费神,问题描述如下:

UserService 中有accountService(AccountService)的引用,而AccountService中有userService(UserService)的引用,属于循环引用,这个在该类中也说明不允许存在循环依赖,但是其实我们用Spring时可以这样注入,如果不看这个细节,那么上面的A依赖B,B依赖A的情况如何去考虑和实现呢?求思路、方法!!!!

 

加载中
0
hunterli
hunterli

我没读过spring源码,我不负责任的瞎猜:

创建A时,先根据无参的构造函数生成一个A的实例,并添加到context中,此时context中存在一个半成品的A;然后创建B实例,此时A的实例(半成品)已经存在,因此B可以正常的创建;然后将创建好的B注入到A中,从而完成A的创建。皆大欢喜

0
mrvoce
mrvoce

引用来自“hunterli”的答案

我没读过spring源码,我不负责任的瞎猜:

创建A时,先根据无参的构造函数生成一个A的实例,并添加到context中,此时context中存在一个半成品的A;然后创建B实例,此时A的实例(半成品)已经存在,因此B可以正常的创建;然后将创建好的B注入到A中,从而完成A的创建。皆大欢喜

B无法正常创建,因为B有A的对象实例。你这个思路是很普遍的思路了。我就特别想问那个A有B的引用,B有A的引用如何将完整的A、B实例注入到双方里面。还是感谢你的讨论。
hunterli
hunterli
没感觉有问题,B创建时,context已经有A的实例,虽然是半成品,但只要B初始化时不用A来做一些其他的工作,只是纯set的话,B就能创建出来。当然这时因为A是不完整的,B也不能称之为完整。但至少构造工作可以继续向下进行。 而你的意思是,在互相构造的时候,双方都要完整,这个感觉够呛。坐等高人...
0
mrvoce
mrvoce

引用来自“mrvoce”的答案

引用来自“hunterli”的答案

我没读过spring源码,我不负责任的瞎猜:

创建A时,先根据无参的构造函数生成一个A的实例,并添加到context中,此时context中存在一个半成品的A;然后创建B实例,此时A的实例(半成品)已经存在,因此B可以正常的创建;然后将创建好的B注入到A中,从而完成A的创建。皆大欢喜

B无法正常创建,因为B有A的对象实例。你这个思路是很普遍的思路了。我就特别想问那个A有B的引用,B有A的引用如何将完整的A、B实例注入到双方里面。还是感谢你的讨论。
如果都不是完整对象那么A、B相互之间方法调用的时候,那岂不是都悲剧了?
hunterli
hunterli
当然,在构造的过程中,是不允许相互调用的,这是必须的限制。
hunterli
hunterli
不是呀,将不完整的B注入到不完整的A中的时候,双方就都完整了。 跟脱离spring,使用java代码构造相互引用的两个对象是一回事呀。
0
mrvoce
mrvoce
Spring高人,在哪里?求教啦。。。。。
0
mrvoce
mrvoce

引用来自“mrvoce”的答案

引用来自“mrvoce”的答案

引用来自“hunterli”的答案

我没读过spring源码,我不负责任的瞎猜:

创建A时,先根据无参的构造函数生成一个A的实例,并添加到context中,此时context中存在一个半成品的A;然后创建B实例,此时A的实例(半成品)已经存在,因此B可以正常的创建;然后将创建好的B注入到A中,从而完成A的创建。皆大欢喜

B无法正常创建,因为B有A的对象实例。你这个思路是很普遍的思路了。我就特别想问那个A有B的引用,B有A的引用如何将完整的A、B实例注入到双方里面。还是感谢你的讨论。
如果都不是完整对象那么A、B相互之间方法调用的时候,那岂不是都悲剧了?

class A{
	B b = new B();
	public void test1(){
		System.out.println("test1");
		b.method1();
	}
 }

class B{

//	A a = new A();//如果解开这里就会出现java.lang.StackOverflowError说明是循环依赖(不允许)
	public void method1(){
		System.out.println("method1");
	}
}
	
public class Test1 {
	public static void main(String[] args) {
		A a = new A();
		a.test1();
	}

}

上面写了例子,但是循环依赖不允许为什么我还是可以看到Spring service层的类进行相互调用,他是怎么屏蔽的呢?Spring高手能否解释下呢。

 

 

0
mrvoce
mrvoce

问题想清楚了。下面是分析

class A{
	B b;
}

class B{
	
	A a;
}

class FactoryBean{
	
	Map<String, Object> beanMap = new HashMap<String, Object>();
	public Object getBean(){
		A a = new A();
		B b = new B();
		try {

		Field f1 = b.getClass().getDeclaredField("a");
		f1.setAccessible(true);
		f1.set(b, a);
		
		Field f = a.getClass().getDeclaredField("b");
		f.setAccessible(true);
		f.set(a,b);
			
		f1.set(b, a);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return a;
	}
}
	
public class Test1 {
	public static void main(String[] args) {
		A a = (A)new FactoryBean().getBean();
		System.out.println("-------");
		System.out.println(a.b);
		System.out.println(a.b.a+"="+a);
	}
}

在反射设置属性时这里是模仿spring的构建bean的情况,A经过初始化后spring检查下面是否有引用如果有引用则进行预先初始化A中的引用依赖,就是B b = new B();但是B需要a的实例,所以直接将A a=new A();中的a设置进去,当然这里的a经过实例化后成员变量a.b是null,然后再设置a中应用的b,此时B中的a是不完整的,然而最后一句f1.set(b, a);再补充设置b中的a,就完整了。运行结果如下:

System.out.println("-------");

System.out.println(a.b+"="+a.b.a.b);

System.out.println(a.b.a+"="+a);

-------

-------

com.ins.base.test.B@ca0b6=com.ins.base.test.B@ca0b6

com.ins.base.test.A@10b30a7=com.ins.base.test.A@10b30a7

说明引用是完整的,不知道这样理解和分析是否正确,请确认下咯。

 

0
mrvoce
mrvoce

引用来自“mrvoce”的答案

问题想清楚了。下面是分析

class A{
	B b;
}

class B{
	
	A a;
}

class FactoryBean{
	
	Map<String, Object> beanMap = new HashMap<String, Object>();
	public Object getBean(){
		A a = new A();
		B b = new B();
		try {

		Field f1 = b.getClass().getDeclaredField("a");
		f1.setAccessible(true);
		f1.set(b, a);
		
		Field f = a.getClass().getDeclaredField("b");
		f.setAccessible(true);
		f.set(a,b);
			
		f1.set(b, a);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return a;
	}
}
	
public class Test1 {
	public static void main(String[] args) {
		A a = (A)new FactoryBean().getBean();
		System.out.println("-------");
		System.out.println(a.b);
		System.out.println(a.b.a+"="+a);
	}
}

在反射设置属性时这里是模仿spring的构建bean的情况,A经过初始化后spring检查下面是否有引用如果有引用则进行预先初始化A中的引用依赖,就是B b = new B();但是B需要a的实例,所以直接将A a=new A();中的a设置进去,当然这里的a经过实例化后成员变量a.b是null,然后再设置a中应用的b,此时B中的a是不完整的,然而最后一句f1.set(b, a);再补充设置b中的a,就完整了。运行结果如下:

System.out.println("-------");

System.out.println(a.b+"="+a.b.a.b);

System.out.println(a.b.a+"="+a);

-------

-------

com.ins.base.test.B@ca0b6=com.ins.base.test.B@ca0b6

com.ins.base.test.A@10b30a7=com.ins.base.test.A@10b30a7

说明引用是完整的,不知道这样理解和分析是否正确,请确认下咯。

 

不加最后 f1.set(b, a);也可以,因为当前范围属于值引用范围,未断开。所以引用有效。
返回顶部
顶部