spring单例bean中依赖了原型bean引发的问题

众所周知,在Spring容器中,bean的scope默认是singleton单例的。

如果在singleton的bean中依赖了prototype的bean,那么会出现下面的问题,原型的bean每次获取的都是同一个对象。

看一个例子:

1)单例Bean:

package com.along.dao;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
 
/**
 * scope默认是singleton
 */
@Repository
public class OrderDao {
 
    @Autowired
    private IndexDao indexDao;
    
    //这里分别打印当前orderDao的hashCode和它所依赖indexDao的hashCode
    public void order(){
        System.out.println("orderDao:"+this.hashCode());
        System.out.println("indexDao:"+indexDao.hashCode());
    }
}

2)原型Bean: 

package com.along.dao;
 
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;
 
@Repository
@Scope("prototype")
public class IndexDao {
	public void test(){
		System.out.println("IndexDao#test()");
	}
}

3)测试:

package com.along.config;
 
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
 
@Configuration
@ComponentScan("com.along")
public class AppConfig {
    public static void main( String[] args ) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(AppConfig.class);
        context.refresh();
        OrderDao orderDao = (OrderDao) context.getBean("orderDao");
    	orderDao.order();
    	orderDao.order();
        context.close();
    }
}

运行:

orderDao:1513712028
indexDao:1018547642
orderDao:1513712028
indexDao:1018547642

原因:因为OrderDao只实例化了一次,那么他只有一次机会为他的依赖IndexDao去设置属性,由于OtderDao是单例的,所以没办法再为IndexDao去设置属性。

解决方法:

在spring官网上介绍了两种解决方法:Core Technologies

在大多数应用程序场景中,容器中的大多数bean都是单例的。当一个单例bean需要与另一个单例bean协作,或者一个非单例bean需要与另一个非单例bean协作时,通常通过将一个bean定义为另一个bean的属性来处理依赖关系。当bean的生命周期不同时,就会出现问题。假设单例bean A需要使用非单例(原型)bean B,可能是在A上的每个方法调用上。容器只创建单例bean A一次,因此只有一次机会设置属性。容器不能每次需要bean B的新实例时都向bean A提供一个。

1)实现ApplicationContextAware接口:

您可以通过实现applicationcontext - ware接口,以及在bean A每次需要bean B实例时对容器发出getBean(“B”)调用来让bean A知道容器。

package com.along.dao;
 
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Repository;
 
@Repository
public class OrderDao implements ApplicationContextAware {
 
	private ApplicationContext applicationContext;
 
	@Autowired
	public IndexDao indexDao;
 
	public void order(){
		System.out.println("orderDao:"+this.hashCode());
		indexDao = (IndexDao) applicationContext.getBean("indexDao");
		System.out.println("indexDao:"+indexDao.hashCode());
	}
 
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}
}

实现 ApplicationContextAware 接口的,并重写setApplicationContext方法(),并通过applicationContext获取bean,每次获取到的就是不同的bean。

这个是第一种实现方法,但是这个严重依赖于Spring的API,侵入性太强。

2)Lookup注解:

package com.along.dao;
 
import org.springframework.beans.factory.annotation.Lookup;
import org.springframework.stereotype.Repository;
 
@Repository
public abstract class OrderDao {
 
	@Lookup("indexDao")
	public abstract IndexDao getIndexDao();
 
	public void order(){
		System.out.println("orderDao:"+this.hashCode());
		System.out.println("indexDao:"+getIndexDao().hashCode());
	}
}


用于个人学习记录

转载自

spring单例bean中依赖了原型bean引发的问题_赶路人儿的博客-CSDN博客

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值