单例会话bean(1)

EJB3.1之前在会话bean的种类中是没有单例会话bean的,有的只是有状态会话bean以及无状态会话bean。毋庸置疑无状态会话bean以其优秀的性能被普遍使用,但是人们发现在无状态会话bean在使用过程中有两个最常值得关注的问题。按照官方一点儿的话说那就是一、bean池的感知开销。二、无法通过静态字段共享状态。其中第二点很好理解,因为无状态会话bean在每次请求的时候都需要从实例池中拿到一个实例对请求进行服务所以不可能存在像普通java变量那样通过共享静态字段共享不同请求之间的状态。第一点所谓的感知开销是指客户端发起请求的时候bean池不知道还有多少个实例可用,bean池所做的就是将请求放在一个队列中然后等待可用的实例,然后将这个实例拿出来对请求进行服务。

单例会话bean的出现实现了单个共享的bean实例,为上面两个问题提供了解决方案,这个共享bean既可以并发访问(解决第一个关于bean池感知开销的问题),也可以作为一种共享状态的机制(共享不同会话之间的状态)。单例会话bean与无状态会话bean的生命周期回调是相同的但生命周期是完全不同的,为了能够进行同步在单例会话bean中还了复杂的开发人员控制锁(developer-controlledlocking)。

与其他会话bean不同,单例会话bean在应用程序初始化期间迅速创建单例,同时在应用程序关闭之前一直存在。可以这么认为,当应用程序启动这个单例就一直存在知道服务器停止。也就是说单例会话bean一旦创建了,它就将在容器删除它之前一直存在,无论在业务方法执行过程中是否发生任何异常。这是它与其他会话bean类型之间的一个关键差异,因为永远不会在系统异常事件中重新创建这种bean实例。

因为单例会话bean的声明周期很长,并且能够共享实例,所以常见应用程序状态的理想储存位置就落在了它的头上,无论是只读(read-only)状态还是读写(read-write)状态。为了确保访问这种状态,单例会话bean提供了许多并发选项,它们取决于应用程序开发人员的需要。考虑到性能,方法可能完全不同步,或者由容器自动地锁定和管理。

1.定义单例会话bean

和无状态和有状态会话bean的模型一样,单例会话bean使用@Singleton注解来定义。单例会话bean可以包括一个本地业务接口或者使用一个无接口视图。下面代码显示了一个简单的具有无接口视图的单例会话bean,用于跟踪Web站点的访问次数。

@Singleton
public class HitCounter {
	int count;

	public void increment() { ++count; }
	
	@Lock(LockType.READ)
	public int getCount() { return count; }

    public void reset() { count = 0; }
}

如果将上面程序中的HitCounterbean与前面定义的无状态与有状态会话bean进行比较,那么立刻可以看到两个差异。与无状态会话bean不同,它存在计数字段形式的状态,用于捕获访问计数(保存了会话的状态,而且在不同会话之间是共享的)。与有状态会话bean也不同,没有包含@Remove注解以标识用于完成会话的业务方法(表明单例会话bean不会被销毁)。

默认情况下,容器将管理业务方法的同步以确保不会发生数据破坏。在此例中,这意味着对于bean的所有访问进行序列化,从而保证在任何时间只有一个客户端调用该实例的业务方法。

单例会话bean的生命周期关系到整个应用程序的生命周期。容器决定何时创建单例实例的时间,(如果该bean同时包括@Startup注解,那么应用程序将会强制在启动时迅速初始化这个单例会话bean的实例)。容器当然也可以创建不被@Startup注解标记的在系统应用程序启动时初始化的singleton,但这是特定于不同的服务器供应商的,JavaEE中没有做表述。

当多个单例会话bean互相依赖时,需要告知容器对它们进行实例化的顺序。这时可以通过在bean类中的添加@DependsOn注解来实现,其中列出了其他必须提前创建的单例会话bean的名称(如果多个记得逗号隔开)。

<think>嗯,用户问的是“bean”,首先我需要确定他们指的是Spring框架中的Bean。可能用户对Spring的Bean作用域不太熟悉,或者在使用过程中遇到了相关问题。我需要先回忆一下Spring中的Bean作用域类型,特别是的作用域。 首先,模式在Spring中默认的作用域,这意味着每个Spring容器中,一个Bean定义对应一个实。但要注意,这里的和设计模式中的有所不同,设计模式中的是每个类加载器一个实,而Spring的是每个容器一个实。这点可能需要特别说明,避免混淆。 接下来,用户可能想知道Bean的适用场景。通常,无状态Bean适合用,比如Service层、DAO层的类,因为它们不保存用户的状态,可以安全地被多个线程共享。但如果Bean有状态,使用可能导致线程安全问题,这时候可能需要考虑其他作用域,比如原型(prototype)。 然后,配置方式。用户可能想知道如何显式配置作用域,虽然在Spring中默认就是,但显式配置可以通过XML或者注解。比如在XML中使用scope属性,或者在Java配置中使用@Scope注解。需要给出具体的子,这样用户更容易理解。 还有生命周期的问题,Bean的生命周期和容器一致,容器启动时初始化,容器销毁时销毁。而原型Bean每次请求都会创建新的实,容器不管理其销毁。这点对资源管理很重要,用户需要注意。 可能用户在使用过程中遇到了线程安全的问题,比如Bean中使用了实变量,导致并发时数据错乱。这时候需要提醒用户检查Bean是否有状态,并建议使用ThreadLocal或者改变作用域为原型。 另外,用户可能对Bean的依赖注入有疑问,比如Bean依赖原型Bean时,如何确保每次获取的是新的原型实。这时候可能需要提到使用@Lookup注解或者方法注入的方式来解决。 还要考虑用户是否有Spring Boot的使用经验,因为在Spring Boot中配置Bean的方式可能更倾向于注解和自动配置,这时候需要调整子以适应不同的配置方式。 总结一下,回答的结构需要包括Bean的定义、作用域、配置方式、生命周期、线程安全以及适用场景,可能还需要对比其他作用域,帮助用户全面理解。同时,要使用用户友好的语言,避免过于技术化的术语,但必要时给出示代码,如XML或注解配置,让用户能直接应用。</think>### Bean 介绍 在 Spring 框架中,**(Singleton)** 是 Bean 的一种作用域(Scope),表示整个 Spring 容器中只有一个 Bean。这是 Spring 默认的作用域。 --- #### 1. 核心特性 - **唯一性** Bean 在容器中仅初始化一次,所有依赖注入或通过容器获取的实都是同一个对象。 如: ```java @Component @Scope("singleton") // 显式声明(默认可省略) public class UserService { ... } ``` - **生命周期与容器绑定** - 初始化:容器启动时创建(可通过 `@Lazy` 延迟初始化)。 - 销毁:容器关闭时销毁。 --- #### 2. 适用场景 - **无状态对象** 如工具类、服务类(Service)、数据访问类(DAO),因为它们不保存用户状态,线程安全风险低。 - **高频率调用对象** 模式减少重复创建开销,提高性能。 --- #### 3. 注意事项 - **线程安全问题** 若 Bean 包含共享变量(如成员变量),多线程并发操作可能导致数据不一致。 **解决方案**: - 使用局部变量或 ThreadLocal。 - 避免保存用户状态。 - **依赖原型 Bean 时的陷阱** 若 Bean 依赖原型 Bean,原型 Bean 仅在初始化时注入一次,后续不会更新。 **解决方案**: - 通过方法注入(`@Lookup` 注解)或 `ObjectFactory`。 --- #### 4. 配置方式 - **XML 配置** ```xml <bean id="userService" class="com.example.UserService" scope="singleton"/> ``` - **注解配置** ```java @Bean @Scope("singleton") public UserService userService() { return new UserService(); } ``` --- #### 5. 与其他作用域对比 | 作用域 | 特点 | 典型场景 | |--------------|-----------------------------|------------------------| | **Singleton** | 容器内唯一实 | 无状态服务、工具类 | | **Prototype** | 每次请求创建新实 | 有状态对象(如用户会话)| | **Request** | 每个 HTTP 请求创建一个实 | Web 应用请求处理 | | **Session** | 每个 HTTP Session 一个实 | 用户登录状态管理 | --- #### 6. 验证行为 ```java public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); UserService bean1 = context.getBean(UserService.class); UserService bean2 = context.getBean(UserService.class); System.out.println(bean1 == bean2); // 输出 true } ``` --- ### 总结 Bean 是 Spring 中高效管理无状态对象的首选方式,但需注意线程安全和依赖注入问题。合理使用可显著提升应用性能,避免资源浪费。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值