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 @ 2022-07-12 12:31  Mars.wang  阅读(587)  评论(0)    收藏  举报