Spring Bean 作用域

来源 说明 目的
singleton 默认 Spring Bean 作用域,一个 BeanFactory 有且仅有一个实例
prototype 原型作用域,每次依赖查找和注入生成新的 Bean 对象
request 将 Spring Bean 存储在 ServletRequest 上下文中 给模板引擎用的
session 将 Spring Bean 存储在 HttpSession 中 给模板引擎用的
application 将 Spring Bean 存储在 ServletContext 中 给模板引擎用的

补充知识:
JSP 四大作用域:当前页面、当前请求、当前会话,当前应用(JSP 四大作用域详解

singleton & prototype Bean 作用域

BeanDefinition 中有 isSingleton 和 isPrototype 的判断,

结论

结论一:

  • Singleton Bean 无论依赖查找还是依赖注入,均为同一个对象
  • Prototype Bean 无论依赖查找还是依赖注入,均为新生成的对象

结论二:

  • 如果依赖注入集合类型的对象,Singleton Bean 和 Prototype Bean 均会存在一个
  • Prototype Bean 有别于其他地方的依赖注入 Prototype Bean

结论三:

  • 无论是 Singleton 还是 Prototype Bean 均会执行初始化方法回调
  • 不过仅 Singleton Bean 会执行销毁方法回调(Singleton Bean 是一对一; Prototype Bean 相当于 bean 和对象的关系一对多,容器没法映射)
  • 但是 Prototype Bean 可以手动销毁

相关代码

BeanScopeDemo.class

  1. /**
  2. * Bean 作用域示例
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class BeanScopeDemo implements DisposableBean {
  8. // 结论一:
  9. // Singleton Bean 无论依赖查找还是依赖注入,均为同一个对象
  10. // Prototype Bean 无论依赖查找还是依赖注入,均为新生成的对象
  11. // 结论二:
  12. // 如果依赖注入集合类型的对象,Singleton Bean 和 Prototype Bean 均会存在一个
  13. // Prototype Bean 有别于其他地方的依赖注入 Prototype Bean
  14. // 结论三:
  15. // 无论是 Singleton 还是 Prototype Bean 均会执行初始化方法回调
  16. // 不过仅 Singleton Bean 会执行销毁方法回调
  17. @Bean
  18. // 默认 scope 为 singleton
  19. public static UserForBeanScope singletonUser() {
  20. return createUser();
  21. }
  22. @Bean
  23. @Scope(ConfigurableListableBeanFactory.SCOPE_PROTOTYPE)
  24. public static UserForBeanScope prototypeUser() {
  25. return createUser();
  26. }
  27. @Autowired
  28. @Qualifier("singletonUser")
  29. public UserForBeanScope singletonUser;
  30. @Autowired
  31. @Qualifier("singletonUser")
  32. public UserForBeanScope singletonUser1;
  33. @Autowired
  34. @Qualifier("singletonUser")
  35. public UserForBeanScope prototypeUser;
  36. @Autowired
  37. @Qualifier("prototypeUser")
  38. public UserForBeanScope prototypeUser1;
  39. @Autowired
  40. @Qualifier("prototypeUser")
  41. public UserForBeanScope prototypeUser2;
  42. @Autowired
  43. private Map<String, UserForBeanScope> users;
  44. @Autowired
  45. private ConfigurableListableBeanFactory beanFactory;// Resolvable Dependency
  46. private static UserForBeanScope createUser() {
  47. UserForBeanScope userForBeanScope = new UserForBeanScope();
  48. userForBeanScope.setId(System.nanoTime());
  49. return userForBeanScope;
  50. }
  51. public static void main(String[] args) {
  52. // 创建 BeanFactory 容器
  53. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
  54. // 注册 配置类(配置类也是 Spring 的 Bean)
  55. applicationContext.register(BeanScopeDemo.class);
  56. // 销毁方式一,不建议使用,因为回调是要将 bean 对象返回
  57. applicationContext.addBeanFactoryPostProcessor(beanFactory -> {
  58. beanFactory.addBeanPostProcessor(new BeanPostProcessor() {
  59. @Override
  60. public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  61. System.out.printf("%s Bean 名称:%s 在初始化后回调...%n", bean.getClass().getName(), beanName);
  62. return bean;
  63. }
  64. });
  65. });
  66. // 启动 Spring 应用上下文
  67. applicationContext.refresh();
  68. // 结论一与结论二演示
  69. scopedBeanByLookUp(applicationContext);
  70. scopedBeanByInject(applicationContext);
  71. // 关闭 Spring 应用上下文
  72. applicationContext.close();
  73. }
  74. /**
  75. * 依赖查找
  76. *
  77. * @param applicationContext 应用程序上下文
  78. */
  79. private static void scopedBeanByLookUp(AnnotationConfigApplicationContext applicationContext) {
  80. for (int i = 0; i < 3; i++) {
  81. UserForBeanScope singletonUser = applicationContext.getBean("singletonUser", UserForBeanScope.class);
  82. System.out.println("singletonUser = " + singletonUser);
  83. UserForBeanScope prototypeUser = applicationContext.getBean("prototypeUser", UserForBeanScope.class);
  84. System.out.println("prototypeUser = " + prototypeUser);
  85. }
  86. }
  87. private static void scopedBeanByInject(AnnotationConfigApplicationContext applicationContext) {
  88. BeanScopeDemo beanScopeDemo = applicationContext.getBean(BeanScopeDemo.class);
  89. System.out.println("beanScopeDemo.singletonUser = " + beanScopeDemo.singletonUser);
  90. System.out.println("beanScopeDemo.singletonUser1 = " + beanScopeDemo.singletonUser1);
  91. System.out.println("beanScopeDemo.prototypeUser = " + beanScopeDemo.prototypeUser);
  92. System.out.println("beanScopeDemo.prototypeUser1 = " + beanScopeDemo.prototypeUser1);
  93. System.out.println("beanScopeDemo.prototypeUser2 = " + beanScopeDemo.prototypeUser2);
  94. System.out.println("beanScopeDemo.users = " + beanScopeDemo.users);
  95. }
  96. // 销毁方式二:实现 DisposableBean 接口,重写 destroy 方法进行销毁
  97. @Override
  98. public void destroy() throws Exception {
  99. System.out.println("当前 BeanScopeDemo 中的 Prototype Bean 正在销毁中...");
  100. this.prototypeUser.destory();
  101. this.prototypeUser1.destory();
  102. this.prototypeUser2.destory();
  103. // 获取 BeanDefinition
  104. for (Map.Entry<String, UserForBeanScope> entry : this.users.entrySet()) {
  105. String beanName = entry.getKey();
  106. BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
  107. if (beanDefinition.isPrototype()) { // 如果当前 Bean 是 prototype scope
  108. UserForBeanScope userForBeanScope = entry.getValue();
  109. userForBeanScope.destory();
  110. }
  111. }
  112. System.out.println("当前 BeanScopeDemo 中的 Prototype Bean 销毁完成");
  113. }
  114. }

User.Class

  1. /**
  2. * 用户
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class UserForBeanScope implements BeanNameAware {
  8. // 通过实现 BeanNameAware 接口对 bean 名称修改
  9. private Long id;
  10. private String name;
  11. /**
  12. * 当前 Bean 的名称
  13. */
  14. private transient String beanName;
  15. public Long getId() {
  16. return id;
  17. }
  18. public void setId(Long id) {
  19. this.id = id;
  20. }
  21. public String getName() {
  22. return name;
  23. }
  24. public void setName(String name) {
  25. this.name = name;
  26. }
  27. @Override
  28. public String toString() {
  29. return "User{" +
  30. "id=" + id +
  31. ", name='" + name + '\'' +
  32. '}';
  33. }
  34. // 结论三演示
  35. @PostConstruct
  36. public void init() {
  37. System.out.println("User Bean [" + beanName + "] 初始化……");
  38. }
  39. @PreDestroy
  40. public void destory() {
  41. System.out.println("User Bean [" + beanName + "] 销毁……");
  42. }
  43. @Override
  44. public void setBeanName(String name) {
  45. this.beanName = name;
  46. }
  47. }

request & session Bean 作用域

request:前端每次请求是一个新的对象,创建新生成对象用的对象是同一个经过 CGLIB 增强的对象
session:每次会话是一个新的对象,创建新生成对象用的对象是同一个经过 CGLIB 增强的对象

application Bean 作用域

个人学下来感觉就是为了方便直接获取,作用类似单例。未深究

自定义 Bean 作用域

先实现 Scope 接口

org.springframework.beans.factory.config.Scope

后注册

  1. API:org.springframework.beans.factory.config.ConfigurableBeanFactory#registerScope
  2. 配置:
    1. <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
    2. <property name="scopes">
    3. <map>
    4. <entry key="...">
    5. </entry>
    6. </map>
    7. </property>
    8. </bean>

    相关代码

课外资料