栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

8. Spring Bean 作用域

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

8. Spring Bean 作用域

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

主要是 Singleton 和 Prototype 这两种,其余的是在后续版本中才加入的,并且在 BeanDefinition 中也只有 sigleton 和 prototype 两种作用域的定义

8.1 Singleton

在一定范围内是唯一的,Spring 中就是在一个 BeanFactory 内部是唯一的

8.2 Prototype
@Configuration
@PropertySource("default.properties")
public class BeanScopeDemo {
​
    @Value("${usr.name:default}")
    private String name;
​
    @Value("${usr.age:28}")
    private int age;
​
    @Bean
    public User singletonUser() {
        return new User(this.name, this.age);
    }
​
    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public User prototypeUser() {
        return new User(this.name, this.age);
    }
​
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(BeanScopeDemo.class);
​
        context.refresh();
​
        System.out.println(context.getBean("singletonUser", User.class) == context.getBean("singletonUser", User.class));
        System.out.println(context.getBean("prototypeUser", User.class) == context.getBean("prototypeUser", User.class));
​
        context.close();
    }
}
​
public class User implements BeanNameAware {
​
    private transient String beanName;
    private String name;
    private int age;
​
    public User() {
    }
​
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public int getAge() {
        return age;
    }
​
    public void setAge(int age) {
        this.age = age;
    }
​
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }
​
    @PostConstruct
    public void init() {
        System.out.println("用户 Bean[" + beanName + "]初始化...");
    }
​
    @PreDestroy
    public void destroy() {
        System.out.println("用户 Bean[" + beanName + "]销毁...");
    }
​
    @Override
    public void setBeanName(String name) {
        this.beanName = name;
    }
}
​
// 运行结果:
用户 Bean[singletonUser]初始化...
true
用户 Bean[prototypeUser]初始化...
用户 Bean[prototypeUser]初始化...
false
用户 Bean[singletonUser]销毁...

Spring 容器没有办法管理 protoType Bean 完整的生命周期,也没有办法记录实例的存在。销毁回调方法将不会执行,可以利用 BeanPostProcessor 进行清扫工作。

结论:

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

  2. 如果依赖注入集合类型对象,Singleton Bean 和 Prototype Bean 均会存在一个且只有一个

  3. 无论是 Singleton 还是 Prototype Bean 均会执行初始化方法回调,不过仅 Singleton Bean 会执行销毁方法回调

8.3 Request

配置

  • XML——

  • Java 注解——@RequestScope 或 @Scope(WebApplicationContext.SCOPE_REQUEST)

实现

  • API——RequestScope

对象会被代理,页面渲染时是新对象,通过 Model 传递给 JSP 的对象每次都是新的,但是代理对象是不变的

8.4 Session

配置

  • XML——

  • Java 注解——@SessionScope 或 @Scope(WebApplicationContext.SCOPE_SESSION)

实现

  • API——SessionScope

对象会被代理,页面渲染时是新对象,通过 Model 传递给 JSP 的对象在每次会话中都是相同的,不同会话中不同,但是代理对象是不变的

8.5 Application

配置

  • XML——

  • Java 注解——@ApplicationScope 或 @Scope(WebApplicationContext.SCOPE_APPLICATION)

实现

  • API——ServletContextScope

JSP EL 变量搜索路径 page -> request -> session -> application(ServletContext)

ApplicationContext 作用域其实就是将 Bean 放到 ServletContext 中进行存储,因此我们不必使用 Model 进行数据的传输,可以直接在 JSP 页面中使用 Application 作用域的bean

8.6 自定义 Bean 作用域
  • 实现 Scope

    • org.springfamework.beans.factory.config.Scope

  • 注册 Scope

    • API——org.springframework.beans.factory.config.ConfigurableBeanFactory#registerScope

    • 配置

      
          
              
                  
              
          
      
8.7 面试题

8.7.1 Spring 内建的 Bean 作用域有几种?

六种:sigleton、prototype、request、session、application 以及 websocket

从设计模式:单例和原生(原型)

从web模式:request、session、application、websocket

8.7.2 singleton Bean 是否在一个应用中是唯一的

不是,只是在一个 BeanFactory 中是唯一的,整个应用可能包含多个应用上下文(层次上下文),不同上下文中互不影响

同样的,一个静态字段在 JVM 中是否唯一?不是唯一的,静态字段相对于 ClassLoader 唯一,但是一个 JVM 进程可能包含多个 ClassCloader

8.7.3 application 作用域 Bean 是否能被其他方案替代

是可以的,实际上,application bean 与 singleton bean 没有本质区别,无非是在某处进行了存储,跟 Ioc 容器中的 bean 是同一个

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/855083.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号