目录
在 Spring 中 Bean 是最核心的操作,接下来我们来分析 Bean 作用域的问题
现在有一个公共 Bean(默认是单例模式)的 User 类:
- @Component
- public class Users {
- @Bean(name = "user")
- @Scope("prototype") //作用域
- public User getUser() {
- User user = new User();
- user.setId(5);
- user.setName("小温");
- return user;
- }
- }
A 用户进行了修改操作(UserController1 类):
- @Controller
- public class UserController1 {
- @Autowired
- private User user;
-
- public void doMethod() {
- User user2 = user;
- System.out.println("UserController1 修改之前:User -> " + user);
- user2.setName("三三");
- System.out.println("UserController1 修改之后:User -> " + user);
- }
- }
B 用户使用公共 Bean(UserController2 类):
- @Controller
- public class UserController2 {
- @Autowired
- private User user;
-
- public void doMethod() {
- System.out.println("UserController2 :User -> " + user);
- }
- }
打印 A 用户和 B 用户公共 Bean 的值:
- public class App {
- public static void main(String[] args) {
- ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
- UserController1 userController1 = context.getBean("userController1", UserController1.class);
- userController1.doMethod();
-
- UserController2 userController2 = context.getBean("userController2", UserController2.class);
- userController2.doMethod();
- }
- }
此时我们发现 B 用户打印的是修改后的值:因为 Bean 默认情况下是单例状态(singleton),也就是所有人使用的都是同⼀个对象,之前我们学单例模式的时候都知道,使用单例可以很大程度上提高性能,所以在 Spring 中 Bean 的作用域默认也是 singleton 单例模式。
Bean 的作用域是指 Bean 在 Spring 整个框架中的某种行为模式。 比如 singleton 单例作用域,就表示 Bean 在整个 Spring 中只有⼀份,它是全局共享的,那么当其他人修改了这个值之后,那么另一个人读取到的就是被修改的值。
1️⃣singleton 单例模式(默认的作用域)
该作用域下的 Bean 在 IoC 容器中只存在一个实例:获取 Bean(即通过 applicationContext.getBean等方法获取)及装配 Bean 都是同⼀个对象
单例模式的 Bean 是线程安全的吗? 不是(所有人都可以进行操作),使用 ThreaddLocal(本地线程变量)
2️⃣prototype:原型作用域(多例作用域)
每次对该作用域下的 Bean 的请求都会创建新的实例:获取Bean(即通过 applicationContext.getBean 等方法获取)及装配 Bean(即通过@Autowired 注入)都是新的对象实例
3️⃣request:请求作用域
每次http请求会创建新的Bean实例,类似于prototype;只适用于 Spring MVC 项目(Spring Web)
4️⃣session:会话作用域
在⼀个http session中,定义⼀个Bean实例;⽤户回话的共享Bean, 比如:记录⼀个⽤户的登陆信息;只适用于 Spring MVC 项目(Spring Web)
5️⃣application:应用作用域
在⼀个http servlet Context中,定义⼀个Bean实例;只适用于 Spring MVC 项目(Spring Web)
6️⃣websocket:websocket 作用域,只适用于 websocket 作用域(了)
使用 @Scope 标签声明 Bean 的作用域
1️⃣@Scope("prototype")
2️⃣@Scope("ConfigurableBeanFactory.SCOPE_PROTOTYPE")
示例:
- public class BeanLifeComponent implements BeanNameAware {
- @Override
- public void setBeanName(String s) {
- System.out.println("执行了 BeanNameAware -> " + s);
- }
-
- //初始化方法——注解
- @PostConstruct
- public void doPostConstruct() {
- System.out.println("执行了 @PostConstruct");
- }
-
- //初始化方法——xml
- public void myInit() {
- System.out.println("执行了 myinit");
- }
-
- @PreDestroy
- public void doPreDestroy() {
- System.out.println("执行了 @PreDestroy");
- }
-
- public void sayHi() {
- System.out.println("使用 Bean");
- }
- }
xml 配置:
- "1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:content="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
- <content:component-scan base-package="spring.java.demo">content:component-scan>
- <bean id="mybean" class="BeanLifeComponent" init-method="myInit">bean>
- beans>
测试类:
- public class BeanLifeTest {
- public static void main(String[] args) {
- ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
- BeanLifeComponent component = context.getBean("mybean", BeanLifeComponent.class);
- component.sayHi();
- context.close();
- }
- }