spring非单例模式

Posted by hcy on June 28, 2021

spring非单例模式

​ 一般情况下,使用spring的bean都是单例模式的,默认情况下就是如此。单例模式的bean都是无状态的,但是面对复杂场景下,希望bean内能存储状态,这种情况下就不能够使用单例模式了。

spring提供了 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) 注解,可以选择是单例模式还是每次使用都创建一个,用法如下。

下面提供的AService作用域是prototype的,其会在每次使用时创建一个新的,Controller1 Controller2内注入的AService是两个不同的示例,AService的构造方法也没调用两次。

1
2
3
4
5
6
7
8
9
@Service
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class AService {

    public AService() {
        System.out.println("AService 被创建");
    }

}
1
2
3
4
5
6
7
@Controller
public class Controller1 {

    @Resource
    AService aService;

}
1
2
3
4
5
6
7
@Controller
public class Controller2 {

    @Resource
    AService aService;

}

上面是一种场景,他将AService注入不同类时,都创建一个新的实例,但是一旦注入完成后,AService对象就不会再改变了,如果想要方法级别每次使用时都创建一个新的,可以向下面这样做。

做法1,手动获取

这种做法不太好,向类中注入一个BeanFactory,每次方法中使用时,从BeanFactory中获取,因为我们的作用域是原型模式,所以每次获取的都会新建一个,满足我们的要求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Controller
public class Controller1 implements BeanFactoryAware {

    BeanFactory beanFactory;

    public void doSomething() {
        AService aService = beanFactory.getBean(AService.class);
        System.out.println(aService);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }
}

做法2,通过ObjectProvider获取

注入泛型类型为AService的ObjectProvider,想要使用时,调用其getObject()方法,其内部会像上面手动获取一样,从容器中获取,也能满足我们的要求。 此种方式更优雅一点。

1
2
3
4
5
6
7
8
9
10
11
@Controller
public class Controller1 {

    @Resource
    ObjectProvider<AService> objectProvider;

    public void doSomething() {
        AService aService = objectProvider.getObject();
        System.out.println(aService);
    }
}

总结

本文主要想解决的问题是,某个类想要被Spring管理,但又是非单例的,我们如何优雅使用该类。 我们需要了解的是Spring的作用域,他又两种,一种是单例模式,一种是原型模式,原型模式每次从容器中获取时都会创建一个新的实例。 如果只是使用@Resource注入,那么注入后对象就不会再改变,不能实现每次使用都创建新的对象。 我们可以注入BeanFactory每次使用时手动获取来实现目的。 配合ObjectProvider使用,ObjectProvider帮助我们从容器中获取,可以使代码更优雅。


转载请注明出处:https://www.huangchaoyu.com/2021/06/28/spring非单例模式/