文章目录
- 【Spring】Bean的作用域和生命周期
- Bean的作用域
- 单例设计
- 作用域定义
- 6种作用域
- singleton
- prototype
- request
- session
- application
- websocket
- singletonVSapplication
- 设置作用域@Scope
- Bean的生命周期
- 1. 实例化Bean
- 2.设置属性
- 3. 初始化
- 4.使用Bean
- 5.摧毁Bean
【Spring】Bean的作用域和生命周期
Bean的作用域
单例设计
Bean在默认条件下是单例设计的,就是所有获得的对象其实都是一个,这样做的原因其实是为了节省性能
@Controller
public class UserController {
@Qualifier(value = "user2")
@Autowired
private User user;
public User getUser(){
User newUser=user;
newUser.setName("cxzs");
return newUser;
}
}
对原有的user对象的name进行了更改
@Controller
public class UserController2 {
@Qualifier("user2")
@Autowired
private User user;
public User getUser() {
User newUser=user;
return newUser;
}
}
controller2同样也获取到user2这个对象
最后进行访问这两个controller的getUser方法的时候,我们发现,其实这两个得到的是同一个对象
public class Start {
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
User user=context.getBean("user2",User.class);
System.out.println(user);
UserController userController=context.getBean("userController",UserController.class);
System.out.println(userController.getUser());
UserController2 userController2=context.getBean(UserController2.class);
System.out.println(userController2.getUser());
}
}
所以我们得知,Bean在默认情况下就是单例模式
作用域定义
原来的作用域的定义指的是这个变量,对象可以使用的范围,可以生存的范围,出了这个作用域就无法再使用这个对象了
但是Bean的作用域指的是Bean的行为模式,
比如singleton就是Bean的单例作用域,表示内存中仅仅有一份该对象
6种作用域
Spring容器在实例化对象的同时,也会指定对象的作用域,下面是6种作用域,其中前两种是普通的Spring项目,后四种只针对于SpringMVC项目
- singleton 单例作用域(默认)
- prototype 原型作用域(多例作用域)
- request 请求作用域
- session 会话作用域
- application 全局作用域
- websocket Http的WebSocket作用域
singleton
描述:在使用ApplicationContext.getBean和通过@Autowired获得的都是同一个对象
使用场景:主要用于无状态的Bean,就是不会对Bean中的属性进行更改
备注:是默认条件下的作用域
prototype
描述:在使用ApplicationContext.getBean和通过@Autowired注入时都会重新创建一个变量
使用场景:主要用于有状态的Bean,会对Bean的属性进行更改
request
描述:每一次Http请求都会创建的新的Bean
使用场景:一次Http请求中使用的Bean
备注:主要用于SpringMVC
session
描述:对每一个会话创建出一个新的对象
使用场景:用于创建用户会话的时候,如创建用户的登录会话
备注:主要用于SpringMVC
application
描述:在一个Http Servlet中,使用同一个bean信息
使用场景:一个应用中都使用同一个Bean信息
备注:主要用于SpringMVC
websocket
描述:在一个Http的webSocket中,都是用同一份Bean对象
使用场景:WebSocket的每次会话中,保存了⼀个Map结构的头信息,将⽤来包裹客户端消息头。第⼀次初始化后,知道webSocket结束都是同一个Bean
singletonVSapplication
singleton主要用于Spring core 但是application主要用于SpringMVC
singleton主要时IOc容器,application主要时servlet容器
设置作用域@Scope
只需要在对象的前面加上注解即可.
有以下两种方法:
1 使用ConfigurableBeanFactory的属性
@Bean(name ={"user2","cx"} )
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public User get2(){
User user=new User();
user.setId(2);
user.setName("cx");
return user;
}
2.直接使用注解
@Bean(name ={"user2","cx"} )
@Scope("prototype")
public User get2(){
User user=new User();
user.setId(2);
user.setName("cx");
return user;
}
Bean的生命周期
1. 实例化Bean
就是为Bean开辟一个内存空间
2.设置属性
Bean类的一些属性可能是被依赖注入的,如使用@Autowired注入,构造方法注入,setter注入
3. 初始化
1. 处理各种Aware通知的方法:
BeanNameAware
BeanFactoryAware
ApplicationContextAware
2. 执行BeanPostProcessor初始化前置方法
3. 执行@PostConstruct初始化方法
4. 执行自己实现的init-method方法
5. 执行BeanPostProcessor初始化后置方法
不可以先初始化,再注入属性
因为这样的话,属性的值是Null
4.使用Bean
从Spring中取Bean对象,进行使用
5.摧毁Bean
1. @PreDestroy
2. 重写DisposableBean接口方法
3. destory-method
下面是一些代码的验证:
我们就来看一下BeanLifeTest的生命周期
- 首先继承了BeanNameAware,所以要重写setBeanName
- 还设置了@PostConstructor,构造方法
- 还设置了另外的构造方法init-method
- 设置@PreDestory,设置摧毁方法
package com.beans;
import org.springframework.beans.factory.BeanNameAware;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class BeanLifeTest implements BeanNameAware {
//先处理通知方法
@Override
public void setBeanName(String s) {
System.out.println("执行 BeanNameAware类的方法:setBeanName");
}
//构造方法:
@PostConstruct
public void PostConstruct(){
System.out.println("构造方法:PostConstruct");
}
public void initMethod(){
System.out.println("构造方法:initMethod");
}
//使用方法
public void use(){
System.out.println("使用方法:use");
}
//摧毁方法
@PreDestroy
public void PreDestory(){
System.out.println("摧毁方法:PreDestory");
}
}
Spring的配置文件的信息
设置了init-method,里面写方法名
<?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.beans"></content:component-scan>
<bean id="beanLifeTest" class="com.beans.BeanLifeTest" init-method="initMethod"></bean>
</beans>
Start启动类:获取到BeanLifeTest对象
public class StartBeanLife {
public static void main(String[] args) {
ClassPathXmlApplicationContext context=new
ClassPathXmlApplicationContext("spring-config.xml");
BeanLifeTest beanLifeTest=context.getBean(BeanLifeTest.class);
beanLifeTest.use();
context.destroy();
}
}
执行结果:
执行 BeanNameAware类的方法:setBeanName
构造方法:PostConstruct
构造方法:initMethod
使用方法:use
摧毁方法:PreDestory
我们就知道bean的生命周期的顺序了:
1.aware
2.构造方法
3.使用bean类
4.摧毁bean类