三、Spring注解:@Scope & @Lazy

本文详细介绍了Spring框架中Bean的作用域管理,包括singleton、prototype、request和session四种作用域,以及@Scope和@Lazy注解的具体使用方法。通过示例展示了不同作用域下Bean的实例化行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、@Scope

​ scope有四个作用域,分别为singleton、prototype、request、session。默认是单例模式,即scope=”singleton”。

​ 在使用XML方式声明bean的时候,每一个组件都默认是单实例的。如果你要设置成多实例的话,就需要设置scope属性了。

<bean id="person" class="com.baiding.model.Person" scope="prototype">
        <property name="name" value="lisi"/>
        <property name="age" value="23"/>
</bean>

​ 若使用注解方式,相同的是,当你声明组件的时候,如果没有使用@Scope注解的话,那么组件依然默认是单实例的,相当于添加@Scope(“singleton”)注解。

配置文件:

@Configuration
public class ScopeConfig {

    @Scope(value = "singleton")
    @Bean
    public Person person(){
        System.out.println("注册person...");
        return new Person("zhangsan",22);
    }
}

测试实例:

    @Test
    void test04(){
        ApplicationContext ac = new AnnotationConfigApplicationContext(ScopeConfig.class);
        System.out.println("初始化容器....");
        Object object = ac.getBean("person");
        Object object2 = ac.getBean("person");
        System.out.println(object == object2);
    }

结果:

注册person...
初始化容器....
true
从结果可以看出,当使用@Scope(“singleton”)声明组件的时候,ioc容器启动会调用方法创建对象放到ioc容器中,以后每次获取就是直接从容器中拿。

当使用@Scope(“prototype”)的时候:

配置文件:

@Configuration
public class ScopeConfig {

    @Scope(value = "prototype")
    @Bean
    public Person person(){
        System.out.println("注册person...");
        return new Person("zhangsan",22);
    }
}

测试实例相同,看结果:

初始化容器....
注册person...
注册person...
false
可以看出,当声明为多实例的时候,每次获取得到的对象是不一样的。而且,IOC容器启动时并不会调用方法创建对象放在容器中,而是在每次获取的时候才会调用方法创建对象。

当使用@Scope(“request”)的时候:表示同一次请求创建一个实例。

当使用@Scope(“session”)的时候:表示同一次session创建一个实例。

二、@Lazy

​ 懒加载是专门针对单实例的,也就是说在容器启动的时候并不调用方法创建对象放入容器中,只会在第一次获取对象的时候,会创建对象并放入容器中去,之后就不会在创建对象了。

配置文件:

@Configuration
public class ScopeConfig {

    @Lazy
    @Bean
    public Person person(){
        System.out.println("注册person...");
        return new Person("zhangsan",22);
    }
}

测试实例:

    @Test
    void test04(){
        ApplicationContext ac = new AnnotationConfigApplicationContext(ScopeConfig.class);
        System.out.println("初始化容器....");
//        Object object = ac.getBean("person");
//        Object object2 = ac.getBean("person");
//        System.out.println(object == object2);
    }

结果:

初始化容器....
从上面的结果可以看出,在初始化容器的时候,并没有去创建对象,证明懒加载生效了。

测试实例2:

    @Test
    void test04(){
        ApplicationContext ac = new AnnotationConfigApplicationContext(ScopeConfig.class);
        System.out.println("初始化容器....");
        Object object = ac.getBean("person");
        Object object2 = ac.getBean("person");
        System.out.println(object == object2);
    }

结果:

初始化容器....
注册person...
true
结果显示出在懒加载的情况下,只有在第一次获取对象的时候才会启动方法创建对象放入容器当中去,之后获取对象也就是直接从容器中获取了。
&lt;think&gt;好的,我现在需要帮助用户理解如何在Spring Framework中正确地将@Scope注解与@Autowired一起使用。首先,我得回顾一下用户提供的引用内容,特别是引用1和引用2,因为它们提到了@Autowired和@Scope的相关使用情况。 用户的问题是关于@Scope和@Autowired联合使用的场景和配置方式。我需要先明确这两个注解各自的作用。@Autowired用于自动装配依赖,而@Scope用于定义Bean的作用域,比如单例(singleton)、原型(prototype)等。接下来,我需要考虑它们一起使用时可能出现的问题,比如作用域不同导致的依赖注入问题。 根据引用1,@Autowired默认按类型匹配,如果有多个同类型Bean,需要用@Qualifier来指定名称。但这里的问题是关于作用域的,比如当原型作用域的Bean注入到单例Bean中时,可能不会每次获取新的实例,导致问题。这时候可能需要结合@Scope和@Lookup或者Provider来确保每次获取新实例。 接下来,我需要查看用户提供的引用内容。引用1提到@Autowired通过类型匹配,如果同类型多个Bean需要@Qualifier,这可能与作用域无关,但需要确认。引用2中的示例展示了@Autowired在属性、构造方法和setter方法上的使用,但没有涉及@Scope。引用3提到在@Configuration中使用@Autowired报错,可能涉及作用域或Bean的初始化顺序问题。 现在,我需要整理常见的场景:比如单例Bean注入原型Bean时,如何确保每次获取新实例。这时候可能需要将原型Bean的作用域设置为proxyMode,或者使用Provider。另外,配置类中使用@Bean方法时,如何结合@Scope和@Autowired。 然后,我需要给出具体的配置方式,例如在定义Bean时使用@Scope注解,并说明如何正确注入。比如,使用@Scope(&quot;prototype&quot;)注解在类上,然后在需要注入的地方使用@Autowired,并可能需要结合@Lazy或者Provider来避免单例Bean中的早期初始化问题。 还需要注意可能出现的错误,比如在配置类中直接@Autowired注入一个作用域为原型的Bean,可能会导致问题,这时候需要用方法参数来传递依赖,或者使用其他方式。 最后,总结使用时的注意事项,比如作用域的生命周期管理、代理模式的选择,以及如何测试验证作用域是否生效。同时,可能需要提到在单元测试中如何验证不同作用域Bean的行为是否正确。 现在,我需要将这些思考整理成一个结构清晰的回答,分点说明场景、配置方式和注意事项,并确保引用相关的引用内容。例如,在提到@Autowired的类型匹配时引用[^1],在提到原型作用域注入问题时引用[^2]或[^3]中的相关内容。同时,生成的相关问题需要围绕作用域和自动装配的深入应用展开。&lt;/think&gt;### @Scope注解与@Autowired联合使用详解 #### 一、核心概念说明 1. **@Scope注解**:定义Bean的作用域,例如: - `singleton`:单例模式(默认) - `prototype`:每次请求新实例 - `request`/`session`:Web应用中的作用域 2. **@Autowired注解**:通过类型自动注入依赖,若存在多个同类型Bean需配合`@Qualifier`。 #### 二、典型使用场景与配置方式 **场景1:单例Bean注入原型Bean** 当单例Bean依赖原型Bean时,默认情况下原型Bean仅初始化一次(与单例Bean生命周期绑定)。 **解决方案**: - 使用`@Scope`的代理模式(`proxyMode`): ```java @Component @Scope(value = &quot;prototype&quot;, proxyMode = ScopedProxyMode.TARGET_CLASS) public class PrototypeBean { /*...*/ } @Component public class SingletonBean { @Autowired private PrototypeBean prototypeBean; // 每次调用会生成新实例 } ``` - 或通过`Provider`延迟获取: ```java @Component public class SingletonBean { @Autowired private Provider&lt;PrototypeBean&gt; prototypeBeanProvider; public void doSomething() { PrototypeBean bean = prototypeBeanProvider.get(); } } ``` **场景2:动态配置Bean作用域** 在`@Configuration`类中定义Bean时,结合`@Scope`与`@Autowired`注入依赖: ```java @Configuration public class AppConfig { @Autowired private Environment env; @Bean @Scope(&quot;prototype&quot;) public DataSource dataSource() { // 根据环境变量动态配置数据源 return new DriverManagerDataSource(env.getProperty(&quot;db.url&quot;)); } } ``` 注意:若在`@Configuration`类中直接`@Autowired`注入作用域为`prototype`的Bean,可能因生命周期差异导致问题,建议通过方法参数传递依赖[^3]。 #### 、注意事项 1. **代理模式选择**: - `ScopedProxyMode.TARGET_CLASS`:使用CGLIB代理(适用于类) - `ScopedProxyMode.INTERFACES`:使用JDK动态代理(适用于接口) 2. **循环依赖风险**:复杂作用域组合可能引发循环依赖,需通过`@Lazy`延迟加载解决。 3. **测试验证**:使用`ApplicationContext.getBean()`验证作用域是否生效: ```java PrototypeBean bean1 = context.getBean(PrototypeBean.class); PrototypeBean bean2 = context.getBean(PrototypeBean.class); assertNotSame(bean1, bean2); // 原型作用域应返回不同实例 ``` #### 四、常见错误示例 **错误:单例Bean直接注入原型Bean** ```java @Component public class SingletonService { @Autowired private PrototypeService prototypeService; // 原型Bean被单例持有,仅初始化一次 } ``` **修复方式**:按场景1中方案添加代理或使用`Provider`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值