springboot中使用原型模式(二)
参考:
https://blog.csdn.net/qq_25863845/article/details/123475147
https://www.bbsmax.com/A/pRdBa7E25n/
一、单例对象依赖原型对象
springboot中大部分都是单例,如果一个单例对象中注入了另一个原型对象,那么使用Autowired得到的还是一个单例对象。
原因是单例对象只有一次对象初始化的机会,所以它只能得到第一次注入的原型对象,后面无法再改。
如下:
//car是一个单例 @Component public class Car { @Autowired private Seat seat; public Seat getSeat() { return seat; } } @Component @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class Seat { }
Seat我们定义它是一个原型模式。
测试一下,看是否符合预期
@SpringBootTest(classes= MetaCenterApplication.class) class SeatFactoryTest { @Autowired private Car car; @Test void get() { Seat king = car.getSeat(); Seat king1 = car.getSeat(); System.out.println(king); System.out.println(king1); } }
输出:
cn.jinka.gcdp.metacenter.application.metadata.Seat@12ec5e73
cn.jinka.gcdp.metacenter.application.metadata.Seat@12ec5e73
显而易见,Seat也变成单例了,那怎么办?
还好springboot给我们提供了@LookUp
我们将Car改造一下
@Component public class Car { //这个地方返回null即可,spring会帮我们实现 @Lookup public Seat getSeat(){ return null; } }
重新测试执行一下,发现已经生成了两个不同的对象:
cn.jinka.gcdp.metacenter.application.metadata.Seat@689504b1
cn.jinka.gcdp.metacenter.application.metadata.Seat@bf2f2ce
二、原型对象有多个实现类
假如我们的Seat有多种类型,真皮座椅、绒布座椅等等,这个时候可以构造一个抽象工厂类专门生成椅子。
//抽象椅子 public abstract class Seat { } //真皮座椅 @Component("SeatA") @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class SeatA extends Seat{ } //绒布座椅 @Component("SeatB") @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class SeatB extends Seat{ }
椅子工厂,每次都给汽车生产最新的椅子,@Lookup的参数就是类上面@Component的name
//抽象工厂方法 @Component public abstract class SeatFactory { @Lookup("SeatA") protected abstract Seat getSeatA(); @Lookup("SeatB") protected abstract Seat getSeatB(); }
汽车类
@Component public class Car { @Autowired private SeatFactory seatFactory; public Seat getSeat(){ return seatFactory.getSeatA(); } }
测试类
@SpringBootTest(classes= MetaCenterApplication.class) class SeatFactoryTest { @Autowired private Car car; @Test void get() { Seat king = car.getSeat(); Seat king1 = car.getSeat(); System.out.println(king); System.out.println(king1); } }
输出:
cn.jinka.gcdp.metacenter.application.metadata.SeatA@4c343088
cn.jinka.gcdp.metacenter.application.metadata.SeatA@504ccf42
可以发现,我们通过@Lookup得到了SeatA类型的实例,而且每次生成的都是新的。
备注:
@Lookup底层的实现逻辑还是通过applicationContext.getBean(ClassB.class)这种方式实现的。
@Component public class ClassA implements ApplicationContextAware { private ApplicationContext applicationContext; public void printClass() { System.out.println("This is Class A: " + this); getClassB().printClass(); } public ClassB getClassB() { return applicationContext.getBean(ClassB.class); } public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南