05_Spring Bean作用域 singleton prototype request RequestContextListener与 ContextLoaderListener区别

Spring Bean的作用域

Spring 容器在初始化一个 Bean 的实例时,同时会指定该实例的作用域。
Scope	Description

作用域描述
singleton将每个Spring IoC容器的单个bean定义范围为单个对象实例。
prototype将单个bean定义作用域到任意数量的对象实例。
request将单个bean定义范围到单个HTTP请求的生命周期。也就是说,每个HTTP请求都有它自己的bean实例,它是在单个bean定义的后面创建的。仅在支持web的Spring ApplicationContext中有效。
session将单个bean定义范围到HTTP会话的生命周期。仅在支持web的Spring ApplicationContext中有效。
application将单个bean定义作用于ServletContext的生命周期。仅在支持web的Spring ApplicationContext中有效。
websocket将单个bean定义作用于WebSocket的生命周期。仅在支持web的Spring ApplicationContext中有效

1、singleton

单例模式,使用 singleton 定义的 Bean 在 Spring 容器中只有一个实例,这也是 Bean 默认的作用域。

一般情况下,无状态或者状态不可变的类适合使用单例模式来实现, 不过 Spring 利用 AOP 和 LocalThread 的能力,对非线程安全的变量(状态)进行了特殊处理,使的一些非线程安全的类(持有 Connection 的 DAO 类)变成了线程安全的类 。

<bean id="accountService" class="com.something.DefaultAccountService"/>

<!-- the following is equivalent, though redundant (singleton scope is the default) -->
<bean id="accountService" class="com.something.DefaultAccountService" scope="singleton"/>

Spring 的 ApplicationContext 容器在启动时,会自动实例化所有 singleton 的 Bean 并缓存在容器中 。优点:

  • 对 Bean 提前进行实例化操作会及早发现一些潜在的配置问题
  • Bean 以缓存的方式保存,当运行时调用该 Bean 时就无须再次实例化咯,因此提高运行效率 。

那么可以通过 lazy-init 属性进行控制是否提前实例化:

<bean id="accountService" class="com.something.DefaultAccountService" lazy-init="true"/>

2、prototype

原型模式,每次通过 Spring 容器获取 prototype 定义的 Bean 时,容器都将创建一个新的 Bean 实例。

配置了 scope=“prototype” 的 bean 为非单例作用域。Spring 容器在启动时不实例化 prototype 的 bean ,此外, Spring 容器将 prototype 的 bean 交给调用者后,就不再负责管理它的生命周期。

<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>

注意,singleton和prototype相互依赖的场景,下文翻译原文。
当您将单例范围的bean与原型bean上的依赖项一起使用时,请注意依赖项是在实例化时解析的。因此,如果你把一个原型作用域的bean注入到一个单例作用域的bean中,那么一个新的原型bean就会被实例化,然后依赖性注入到单例bean中。原型实例是提供给单例作用域bean的唯一实例。
但是,假设您希望单例作用域bean在运行时反复获得原型作用域bean的新实例。你不能依赖地将原型作用域的bean注入到你的单例bean中,因为这种注入只发生一次,当Spring容器实例化单例bean并解析和注入它的依赖时。如果您在运行时不止一次地需要原型bean的新实例,请参见方法注入

3、request 、session 、application

  • request :在一次 HTTP 请求中,容器会返回该 Bean 的同一个实例。而对不同的 HTTP 请求,会返回不同的实例,该作用域仅在当前 HTTP Request 内有效。
  • session :在一次 HTTP Session 中,容器会返回该 Bean 的同一个实例。而对不同的 HTTP 请求,会返回不同的实例,该作用域仅在当前 HTTP Session 内有效。
  • application :在一个全局的 HTTP Session 中,容器会返回该 Bean 的同一个实例。该作用域仅在使用 portlet context 时有效。

web.xml 增加request 监听器、过滤器

<web-app>
    ...
    <listener>
        <listener-class>
            org.springframework.web.context.request.RequestContextListener
        </listener-class>
    </listener>
    ...
</web-app>
<!--或者-->
<web-app>
    ...
    <filter>
        <filter-name>requestContextFilter</filter-name>
        <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>requestContextFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    ...
</web-app>

RequestContextListener与 ContextLoaderListener 的区别是:

  • ContextLoaderListener 实现了 ServletContextListener 监听器接口, 它只负责监听 web 容器的启动和关闭事件 。
  • RequestContextListener 实现了 ServletRequestListener 监听器接口,它监听 HTTP 请求事件, Web 服务器的每一次请求都会通知它 。
<bean id="loginAction" class="com.something.LoginAction" scope="request"/>
<bean id="userPreferences" class="com.something.UserPreferences" scope="session"/>
<bean id="appPreferences" class="com.something.AppPreferences" scope="application"/>
@RequestScope
@Component
public class LoginAction {
    // ...
}
@SessionScope
@Component
public class UserPreferences {
    // ...
}
@ApplicationScope
@Component
public class AppPreferences {
    // ...
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EngineerForSoul

你的鼓励是我孜孜不倦的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值