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

本文探讨了Spring框架中singleton和prototype作用域的bean在协作时出现的问题,并提供了两种解决方案:实现ApplicationContextAware接口和使用Lookup注解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

spring中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官网上介绍了两种解决方法:https://docs.spring.io/spring/docs/5.0.14.RELEASE/spring-framework-reference/core.html#beans-factory-method-injection

在大多数应用程序场景中,容器中的大多数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());
	}
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值