Spring 单例模式bean 中引用原型模式bean的一些考虑

本文探讨了Spring中bean的作用域,特别是单例bean引用原型bean的情况。当SingletonA需要每次获取PrototypeB的新实例时,提出了三种解决方法:通过注入ApplicationContext、实现ApplicationContextAware接口以及使用Lookup注解。Spring官方文档对此有详细说明。

一、bean的作用域

众所周知Spring bean的作用范围取值有五种(scope属性控制):

singleton:单例,也是默认值

prototype: 多例,比如让Spring接管struts2的action的时候就必须配置此属性

request: 一次请求以及此次请求的转发

session: 作用范围是一次会话

globalsession: 作用范围是一次全局绘画,比如多台服务器之间需要共用同一个bean的时候就需要此属性。

二、单例的bean引用原型模式的bean

SingletonA 的代码如下

@Service
public class SingletonA {

    @Autowired
    private PrototypeB prototypeB;

    public void printlnB(){
        System.out.println(prototypeB);
    }
}

PrototypeB代码如下

@Service
@Scope(value = "prototype")
public class PrototypeB {

}

测试类

public class SpringTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
        applicationContext.getBean(SingletonA.class).printlnB();
        applicationContext.getBean(SingletonA.class).printlnB();
        applicationContext.getBean(SingletonA.class).printlnB();
    }
}

结果:

com.arvin.learn.spring.PrototypeB@5204062d
com.arvin.learn.spring.PrototypeB@5204062d
com.arvin.learn.spring.PrototypeB@5204062d

这是应该很容易理解,因为SingletonA是单例的,在整个Spring容器里面只会创建一次,在创建的时候给的prototypeB是什么就是什么了。那么问题来了,假如在某些场景下,SingletonA中用到prototypeB的时候,都是要新的,而不是都是同一个。

方法一:在SingletonA注入ApplicationContext,具体实现如下

@Service
public class SingletonA {

    @Autowired
    private PrototypeB prototypeB;

    @Autowired
    private ApplicationContext applicationContext;

    public void printlnB(){
        prototypeB = applicationContext.getBean(PrototypeB.class);
        System.out.println(prototypeB);
    }
}

方法二:SingletonA实现ApplicationContextAware接口

@Service
public class SingletonA implements ApplicationContextAware {

    @Autowired
    private PrototypeB prototypeB;

    private ApplicationContext applicationContext;

    public void printlnB(){
        prototypeB = applicationContext.getBean(PrototypeB.class);
        System.out.println(prototypeB);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext =applicationContext;
    }
}

方法三:使用Lookup注解

@Service
public  class SingletonA {

    @Lookup
    protected  PrototypeB createPrototypeB(){
        return null;
    };

    public void printlnB(){
        PrototypeB prototypeB = createPrototypeB();
        System.out.println(prototypeB);
    }
}

官网上面也有详细的讲解 1.4.6 Lookup Method Injection,地址如下

https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-factory-method-injection

<think>好的,我现在需要回答用户关于Spring框架中Bean作用域的问题,特别是默认的单例模式及其配置方式。首先,我要确认用户的问题核心:Spring Bean的默认作用域是否是单例模式,以及如何配置。根据用户提供的引用内容,引用[4]明确指出Spring默认使用单例模式。因此,我需要先明确这一点,并引用相关文献支持。 接下来,用户可能想知道单例模式原型模式的区别。根据引用[1]和[3],单例模式在整个Spring IoC容器中只有一个实例,而原型模式每次获取都会生成新实例。需要将这些区别清晰地列出,方便用户理解。 然后是关于配置方式的问题。引用[3]提到可以通过XML和注解两种方式配置。我需要分别说明这两种方法的具体步骤,例如在XML中使用`scope`属性,或者在Java配置类中使用`@Scope`注解。同时,要注意默认情况下如果不指定`scope`,Bean就是单例的,这点需要强调。 另外,用户可能对单例模式的应用场景和潜在问题感兴趣。例如,单例模式适合无状态Bean,而原型模式适合有状态的场景。需要提到线程安全和资源管理的问题,帮助用户正确选择作用域。 还要考虑是否需要比较其他作用域,如request、session等,但根据用户的问题,可能只需要聚焦在单例和原型上。不过可以简要提及其他作用域的存在,如引用[4]中提到的五种作用域,但不需要深入。 最后,生成的相关问题需要覆盖用户可能进一步询问的方向,比如配置方法、选择依据、线程安全问题以及单例模式的优缺点。确保问题有针对性,帮助用户深化理解。 现在需要检查是否有遗漏的信息,并确保引用正确。例如,引用[2]提到了Spring源码实现,但用户的问题主要是配置和使用,可能不需要深入源码,但可以提到参考实现细节的文献。同时,保持回答结构清晰,分点说明,使用示例代码块展示配置方式,符合用户要求的格式。</think>### Spring Bean默认作用域及单例模式配置方式 #### 一、默认作用域:单例模式 Spring框架中,**Bean的默认作用域为单例模式**(Singleton)。这意味着在整个Spring IoC容器中,每个Bean定义仅创建一个实例,所有对该Bean的请求都返回同一个对象[^4]。例如: ```xml <!-- XML配置示例,默认scope为singleton --> <bean id="userService" class="com.example.UserService"/> ``` 或通过注解方式: ```java @Component public class UserService { /* ... */ } ``` #### 二、单例模式原型模式的区别 | 特性 | 单例模式(Singleton) | 原型模式(Prototype) | |--------------|---------------------------------------|-------------------------------------| | 实例数量 | 一个容器中仅一个实例 | 每次请求生成新实例 | | 生命周期 | 随容器创建/销毁 | 每次请求独立管理 | | 适用场景 | 无状态服务(如工具类、配置类) | 有状态对象(如用户会话、请求处理) | | 线程安全 | 需自行保证(若共享资源) | 天然隔离(实例独立) | #### 三、配置方式 1. **单例模式(默认无需显式配置)** - **XML配置**: ```xml <bean id="dataSource" class="com.example.DataSource" scope="singleton"/> ``` - **注解配置**: ```java @Component @Scope("singleton") // 可省略 public class DataSource { /* ... */ } ``` 2. **原型模式** - **XML配置**: ```xml <bean id="requestHandler" class="com.example.RequestHandler" scope="prototype"/> ``` - **注解配置**: ```java @Component @Scope("prototype") public class RequestHandler { /* ... */ } ``` #### 四、单例模式的注意事项 - **线程安全**:若单例Bean包含共享变量,需通过同步机制(如`synchronized`)或使用线程局部变量(`ThreadLocal`)保证线程安全。 - **资源占用**:单例Bean在容器生命周期内常驻内存,适合轻量级对象,避免用于大资源持有者。 #### 五、其他作用域(简要扩展) 除了单例和原型Spring还支持: - **Request**:每个HTTP请求生成一个实例(需Web环境)[^4]。 - **Session**:同一HTTP会话共享一个实例。 - **Global Session**:用于Portlet应用(已逐渐淘汰)。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值