Spring Bean 作用域
| 来源 | 说明 | 目的 |
|---|---|---|
| singleton | 默认 Spring Bean 作用域,一个 BeanFactory 有且仅有一个实例 | |
| prototype | 原型作用域,每次依赖查找和注入生成新的 Bean 对象 | |
| request | 将 Spring Bean 存储在 ServletRequest 上下文中 | 给模板引擎用的 |
| session | 将 Spring Bean 存储在 HttpSession 中 | 给模板引擎用的 |
| application | 将 Spring Bean 存储在 ServletContext 中 | 给模板引擎用的 |
补充知识:
JSP 四大作用域:当前页面、当前请求、当前会话,当前应用(JSP 四大作用域详解)
singleton & prototype Bean 作用域
BeanDefinition 中有 isSingleton 和 isPrototype 的判断,
结论
结论一:
- Singleton Bean 无论依赖查找还是依赖注入,均为同一个对象
- Prototype Bean 无论依赖查找还是依赖注入,均为新生成的对象
结论二:
- 如果依赖注入集合类型的对象,Singleton Bean 和 Prototype Bean 均会存在一个
- Prototype Bean 有别于其他地方的依赖注入 Prototype Bean
结论三:
- 无论是 Singleton 还是 Prototype Bean 均会执行初始化方法回调
- 不过仅 Singleton Bean 会执行销毁方法回调(Singleton Bean 是一对一; Prototype Bean 相当于 bean 和对象的关系一对多,容器没法映射)
- 但是 Prototype Bean 可以手动销毁
相关代码
BeanScopeDemo.class
/*** Bean 作用域示例** @author mindartisan.blog.csdn.net* @date*/public class BeanScopeDemo implements DisposableBean {// 结论一:// Singleton Bean 无论依赖查找还是依赖注入,均为同一个对象// Prototype Bean 无论依赖查找还是依赖注入,均为新生成的对象// 结论二:// 如果依赖注入集合类型的对象,Singleton Bean 和 Prototype Bean 均会存在一个// Prototype Bean 有别于其他地方的依赖注入 Prototype Bean// 结论三:// 无论是 Singleton 还是 Prototype Bean 均会执行初始化方法回调// 不过仅 Singleton Bean 会执行销毁方法回调@Bean// 默认 scope 为 singletonpublic static UserForBeanScope singletonUser() {return createUser();}@Bean@Scope(ConfigurableListableBeanFactory.SCOPE_PROTOTYPE)public static UserForBeanScope prototypeUser() {return createUser();}@Autowired@Qualifier("singletonUser")public UserForBeanScope singletonUser;@Autowired@Qualifier("singletonUser")public UserForBeanScope singletonUser1;@Autowired@Qualifier("singletonUser")public UserForBeanScope prototypeUser;@Autowired@Qualifier("prototypeUser")public UserForBeanScope prototypeUser1;@Autowired@Qualifier("prototypeUser")public UserForBeanScope prototypeUser2;@Autowiredprivate Map<String, UserForBeanScope> users;@Autowiredprivate ConfigurableListableBeanFactory beanFactory;// Resolvable Dependencyprivate static UserForBeanScope createUser() {UserForBeanScope userForBeanScope = new UserForBeanScope();userForBeanScope.setId(System.nanoTime());return userForBeanScope;}public static void main(String[] args) {// 创建 BeanFactory 容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();// 注册 配置类(配置类也是 Spring 的 Bean)applicationContext.register(BeanScopeDemo.class);// 销毁方式一,不建议使用,因为回调是要将 bean 对象返回applicationContext.addBeanFactoryPostProcessor(beanFactory -> {beanFactory.addBeanPostProcessor(new BeanPostProcessor() {@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.printf("%s Bean 名称:%s 在初始化后回调...%n", bean.getClass().getName(), beanName);return bean;}});});// 启动 Spring 应用上下文applicationContext.refresh();// 结论一与结论二演示scopedBeanByLookUp(applicationContext);scopedBeanByInject(applicationContext);// 关闭 Spring 应用上下文applicationContext.close();}/*** 依赖查找** @param applicationContext 应用程序上下文*/private static void scopedBeanByLookUp(AnnotationConfigApplicationContext applicationContext) {for (int i = 0; i < 3; i++) {UserForBeanScope singletonUser = applicationContext.getBean("singletonUser", UserForBeanScope.class);System.out.println("singletonUser = " + singletonUser);UserForBeanScope prototypeUser = applicationContext.getBean("prototypeUser", UserForBeanScope.class);System.out.println("prototypeUser = " + prototypeUser);}}private static void scopedBeanByInject(AnnotationConfigApplicationContext applicationContext) {BeanScopeDemo beanScopeDemo = applicationContext.getBean(BeanScopeDemo.class);System.out.println("beanScopeDemo.singletonUser = " + beanScopeDemo.singletonUser);System.out.println("beanScopeDemo.singletonUser1 = " + beanScopeDemo.singletonUser1);System.out.println("beanScopeDemo.prototypeUser = " + beanScopeDemo.prototypeUser);System.out.println("beanScopeDemo.prototypeUser1 = " + beanScopeDemo.prototypeUser1);System.out.println("beanScopeDemo.prototypeUser2 = " + beanScopeDemo.prototypeUser2);System.out.println("beanScopeDemo.users = " + beanScopeDemo.users);}// 销毁方式二:实现 DisposableBean 接口,重写 destroy 方法进行销毁@Overridepublic void destroy() throws Exception {System.out.println("当前 BeanScopeDemo 中的 Prototype Bean 正在销毁中...");this.prototypeUser.destory();this.prototypeUser1.destory();this.prototypeUser2.destory();// 获取 BeanDefinitionfor (Map.Entry<String, UserForBeanScope> entry : this.users.entrySet()) {String beanName = entry.getKey();BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);if (beanDefinition.isPrototype()) { // 如果当前 Bean 是 prototype scopeUserForBeanScope userForBeanScope = entry.getValue();userForBeanScope.destory();}}System.out.println("当前 BeanScopeDemo 中的 Prototype Bean 销毁完成");}}
User.Class
/*** 用户** @author mindartisan.blog.csdn.net* @date*/public class UserForBeanScope implements BeanNameAware {// 通过实现 BeanNameAware 接口对 bean 名称修改private Long id;private String name;/*** 当前 Bean 的名称*/private transient String beanName;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +'}';}// 结论三演示@PostConstructpublic void init() {System.out.println("User Bean [" + beanName + "] 初始化……");}@PreDestroypublic void destory() {System.out.println("User Bean [" + beanName + "] 销毁……");}@Overridepublic void setBeanName(String name) {this.beanName = name;}}
request & session Bean 作用域
request:前端每次请求是一个新的对象,创建新生成对象用的对象是同一个经过 CGLIB 增强的对象
session:每次会话是一个新的对象,创建新生成对象用的对象是同一个经过 CGLIB 增强的对象
application Bean 作用域
个人学下来感觉就是为了方便直接获取,作用类似单例。未深究
自定义 Bean 作用域
先实现 Scope 接口
org.springframework.beans.factory.config.Scope
后注册
- API:org.springframework.beans.factory.config.ConfigurableBeanFactory#registerScope
- 配置:
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"><property name="scopes"><map><entry key="..."></entry></map></property></bean>
相关代码
