Spring 面试 -循环依赖

https://blog.csdn.net/woailaopoqq/article/details/113846328

上面文章介绍了Spring IOC的过程,但是文章中提到的代码未解决循环依赖,本文重点介绍Spring如何解决循环依赖。

上代码:https://download.csdn.net/download/woailaopoqq/15380786

1、模型:存在类关系 A->B->C->A


public class A {
	private String id;
	private B b;
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public B getB() {
		return b;
	}
	public void setB(B b) {
		this.b = b;
	}
	
}

public class B {
	private String id;
	private C c;
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public C getC() {
		return c;
	}
	public void setC(C c) {
		this.c = c;
	}
	
}


public class C {
	private String id;
	private A a;
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public A getA() {
		return a;
	}
	public void setA(A a) {
		this.a = a;
	}
	
	
}


2、XML 配置文件

<?xml version="1.0" encoding="UTF-8"?>

<!-- <!DOCTYPE web-app-config SYSTEM 'file:///c:/rj/controller/WEB-INF/web-app-config-1-0.dtd'> -->

<beans>

	<!-- =========================================================== -->
	<!-- Global Message source. For all servlets. -->
	<!-- =========================================================== -->
	<bean name="messageSource"
		class="com.interface21.context.support.ResourceBundleMessageSource">
		<property name="basename">messages</property>
	</bean>

	<bean name="a" class="com.travelsky.ebuild.spring.A"
		sigleton="true">
		<property name="id">A</property>
		<property name="b"  beanRef="true" >b</property>
	</bean>
	<bean name="b" class="com.travelsky.ebuild.spring.B"
		sigleton="true">
		<property name="id">B</property>
		<property name="c"  beanRef="true" >c</property>
	</bean>
	<bean name="c" class="com.travelsky.ebuild.spring.C"
		sigleton="true">
		<property name="id">C</property>
		<property name="a"  beanRef="true" >a</property>
	</bean>

</beans>

 

3、解决循环依赖

 

 

Spring IOC 过程:

step1:读取xml配置文件,将xml中bean信息解析到BeanDefinition,供后续使用;

step2:通过clazz.newInstance()实例化bean;

step3:利用step1中读取的配置,找到bean-name,bean-setproperty(最终是setProperty) 等信息,通过反射技术对step2生成的bean进行set property;

step4:通过增加两个Map,来解决循环依赖,具体参考代码中说明,最好的方法是将代码运行起来,Debug

     /** 缓存创建完毕的Spring Bean */
    private HashMap sharedInstanceCache = new HashMap();
    // 缓存clazz.newInstance()实例化的bean
    private Map<String, Object> cacheMap = new ConcurrentHashMap<>(16);

 

1、测试入口类

	@Test
	public void testABCA()
	{
		BeanFactory factory = new XmlBeanFactory("applicationContext-ABCA.xml");
		A   a = (A)factory.getBean("a");
		B  b = (B)factory.getBean("b");
		C   c = (C)factory.getBean("c");
	}

2、实例化XmlBeanFactory
public XmlBeanFactory(String filename) throws BeansException {
		try {
			logger.info("Loading XmlBeanFactory from file '" + filename + "'");
			loadBeanDefinitions(new FileInputStream(filename));
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException("Can't open file [" + filename + "]", ex);
		}
	}

3、解析xml中的Bean信息,bean名称,class名称以及property信息,并存储在BeanDefinition中
private void loadBeanDefinitions(Document doc) throws BeansException {
		Element root = doc.getDocumentElement();
		logger.fine("Loading bean definitions");
		NodeList nl = root.getElementsByTagName(BEAN_ELEMENT);
		logger.fine("Found " + nl.getLength() + " <" + BEAN_ELEMENT + "> elements defining beans");
		for (int i = 0; i < nl.getLength(); i++) {
			Node n = nl.item(i);
			loadBeanDefinition((Element) n);
		}
		
		// Ask superclass to eagerly instantiate singletons
		preInstantiateSingletons();
	} 	// loadBeanDefinitions (Document)

4、解决循环依赖


private final synchronized Object getSharedInstance(String name) throws BeansException {
		BeanDefinition bd = getBeanDefinition(name);
		Class beanClass = bd.getBeanClass();
		// Spring Bean是否存在于sharedInstanceCache中
		Object single = this.sharedInstanceCache.get(name);
		if (single != null) {
			return single;
		}
		// Spring Bean 是否已经执行过clazz.newInstance(),但是未设置property
		single = cacheMap.get(name);
		if (single != null) {
			return single;
		}

		//如两个缓存中未查到,则执行过clazz.newInstance(),创建对象,未设置property
		Object beanInstance = BeanUtils.instantiateClass(beanClass);
		// 放入缓存,当设置property时,如碰到循环依赖需要set该property,则使用此时申城的property
		cacheMap.put(name, beanInstance);
		// IOC,执行Spring Bean的set方法设置属性
		Object o = createBean(name, beanInstance);
		//将IOC完毕的Spring Bean放入缓存
		sharedInstanceCache.put(name, beanInstance);
		//移除中间态
		cacheMap.remove(name);
		return o;
	}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值