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;
    }
}
复制代码

 

posted @   Mars.wang  阅读(569)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
点击右上角即可分享
微信分享提示