目录
- 一、Bean作用域作用域
- 1.1 Bean作用域简介
- 1.2 作用域的定义
- 1.3 Bean的6种作用域
- 1.4 设置作用域
- 二、Spring的执行流程和Bean的生命周期
- 2.1 Spring的执行流程
- 2.2 Bean的生命周期
一、Bean作用域作用域
1.1 Bean作用域简介
现在有一个公共的Bean,A用户先使用到这个Bean,并在使用后将Bean修改了,这就是B用户拿到的Bean是A修改后的Bean了,而B期望拿到的确实最原始的Bean
公共的Bean:User对象
@Component
public class UserBeans {
@Bean
public User user(){
User user=new User();
user.setName("zhangsan");
user.setId(100);
return user;
}
}
A用户使用后将name修改成lisi了:
@Controller
@Controller
public class UserControllerA {
@Autowired
private User user;
public User getUser(){
User tmp=user;
System.out.println("A用户修改之前的User.name:"+user.getName());
tmp.setName("lisi");
return tmp;
}
}
B用户使用Bean:
@Controller
public class UserControllerB {
@Autowired
private User user;
public User getUser(){
return user;
}
}
App类打印:
【原因分析】
产生上述情况的原因在于Bean默认情况下是单例状态,也就是所有人使用的都是同一个对象,之所以默认为单例状态是因为性能更高
1.2 作用域的定义
Bean的作用域是指Bean在Spring整个框架中的某种行为模式,比如singleton单例作用域,就表示Bean在整个Spring中只有一份,它是全局共享的,那么当其他人修改了这个值后,别人获取到的就是修改后的值了
1.3 Bean的6种作用域
Spring容器在初始化一个Bean的实例时,同时会指定该实例的作用域。Spring中有6种作用域,后4种基于Spring MVC生效:
- singleton 单例作用域
- prototype 原型作用域
- request 请求作用域
- session 会话作用域
- application 全局作用域
- websocket HTTPWebSokcet作用域
【singleton】
描述:在该作用域下的Bean在IoC容器中只存在一个实例:获取Bean及装配Bean都是同一个对象
使用场景:通常无状态的Bean使用该作用域。无状态表示Bean对象的属性状态不需要更新
Spring默认作用域为singleton
【prototype】
描述:每次都过application.getBean方法或通过注解注入Bean时,通过会创建新的实例,得到的都是新创建的对象
使用场景:通常又状态的Bean使用该作用域
【request】
描述:每次http请求都会创建新的Bean实例
使用场景:一次http请求和响应的共享Bean
【session】
描述:在一个http session中,定义一个Bean实例
使用场景:用户会话的共享Bean
【application】
描述:在⼀个http servlet Context中,定义⼀个Bean实例
使用场景:Web应⽤的上下⽂信息,⽐如:记录⼀个应⽤的共享信息
【websocket】
描述:在⼀个HTTP WebSocket的生命周期中,定义⼀个Bean实例
使用场景:WebSocket的每次会话中,保存了⼀个Map结构的头信息,将用来包裹客户端消息头。第⼀次初始化后,直到WebSocket结束都是同⼀个Bean
【singleton和application的区别】
singleton是SpringCore的作用域,application是Spring Web的作用域
singleton作用于IoC容器,application作用于Servlet容器
1.4 设置作用域
使用@Scope标签生命Bean作用域
@Component
public class UserBeans {
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Bean
public User user(){
User user=new User();
user.setName("zhangsan");
user.setId(100);
return user;
}
}
App中的执行结果:
【补充】
Scope标签有两种设置方式:
- 直接设置值,@Scope(“prototype”)
- 使用枚举设置,@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
二、Spring的执行流程和Bean的生命周期
2.1 Spring的执行流程
2.2 Bean的生命周期
Bean的生命周期分为下面5个部分:
- 实例化Bean(为Bean分配内存空间)
- 设置属性(Bean注入和装配)
- Bean初始化
- 实现了各种Aware通知的方法,如BeanNameAware、BeanFactoryAware、ApplicationContextAware的接口方法
- 执行@PostConstruct初始化方法,依赖注入操作之后执行
- 执行自己指定的init-method方法
- 使用Bean
- 销毁Bean,销毁容器的各种⽅法,如 @PreDestroy、DisposableBean 接口方法、destroy-method。
执行流程如下图所示:
BeanLifeComponent类:
package com.bit;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class BeanLifeComponent implements BeanNameAware {
@PostConstruct
public void postConstruct() {
System.out.println("执⾏ PostConstruct()");
}
public void init() {
System.out.println("执⾏ BeanLifeComponent init-method");
}
@PreDestroy
public void preDestroy() {
System.out.println("执⾏:preDestroy()");
}
@Override
public void setBeanName(String s) { //BeanNameAware接口中的方法
System.out.println("执行BeanName通知");
}
}
spring.xml:
<?xml version="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="com.bit"></content:component-scan>
<bean id="beanLifeComponent" class="com.bit.BeanLifeComponent" init-method="init"></bean>
</beans>
App启动类:
【注意】:设置属性一定要在初始化之前,如果步骤颠倒就可能出现空指针异常
@Service
public class UserService {
public UserService(){
System.out.println("调⽤ User Service 构造⽅法");
}
public void sayHi(){
System.out.println("User Service SayHi.");
}
}
@Controller
public class UserController {
@Resource
private UserService userService;
@PostConstruct
public void postConstruct() {
userService.sayHi(); //在构造方法中使用到属性userService
System.out.println("执⾏ User Controller 构造⽅法");
}
}