Logo

郎哥编程

理解Spring Bean的作用域

2018-08-29 895

本篇介绍Spring Bean实例的作用范围,Spring Bean实例的作用范围由配置项scope限定。通过本篇的学习,可以达成如下目标。

● 应用scope配置项配置Bean的作用域

● 应用单例模式singleton

● 应用原型模式prototype

 

一、作用域scope配置项

作用域限定了Spring Bean的作用范围,在Spring配置文件定义Bean时,通过声明scope配置项,可以灵活定义Bean的作用范围。例如,当你希望每次IOC容器返回的Bean是同一个实例时,可以设置scope为singleton;当你希望每次IOC容器返回的Bean实例是一个新的实例时,可以设置scope为prototype。

scope配置项有5个属性,用于描述不同的作用域。

① singleton

使用该属性定义Bean时,IOC容器仅创建一个Bean实例,IOC容器每次返回的是同一个Bean实例。

② prototype

使用该属性定义Bean时,IOC容器可以创建多个Bean实例,每次返回的都是一个新的实例。

③ request

该属性仅对HTTP请求产生作用,使用该属性定义Bean时,每次HTTP请求都会创建一个新的Bean,适用于WebApplicationContext环境。

④ session

该属性仅用于HTTP Session,同一个Session共享一个Bean实例。不同Session使用不同的实例。

⑤ global-session

该属性仅用于HTTP Session,同session作用域不同的是,所有的Session共享一个Bean实例。

下面重点讨论singleton、prototyp作用域,request、session和global-session类作用域放到Spring MVC章节讨论,这里不再做详细讲述。

二、singleton作用域

singleton是默认的作用域,当定义Bean时,如果没有指定scope配置项,Bean的作用域被默认为singleton。singleton属于单例模式,在整个系统上下文环境中,仅有一个Bean实例。也就是说,在整个系统上下文环境中,你通过Spring IOC获取的都是同一个实例。

配置Bean为singleton作用域的配置代码如下。

<!-- A bean definition with singleton scope -->
<bean id="..." class="..." scope="singleton">
    <!-- collaborators and configuration for this bean go here -->
</bean>

singleton作用域示例:

(1)课程案例新建SingletonTest类文件,添加下面的代码。

package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.milihua.springprogram.business.IocPrincipal;
public class SingletonTest {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ApplicationContext context = new ClassPathXmlApplicationContext("config/dispatcher.xml");
        //声明校长类,并发送通知
        IocPrincipal iocPrincipal = new IocPrincipal();
        String notifyReturn = iocPrincipal.notifyTeacher(context);
        System.out.println(notifyReturn);
       
        //重新声明一个校长类,并发送通知
        IocPrincipal iocPrincipaSecond = new IocPrincipal();
        String notifyReturnSecond = iocPrincipaSecond.notifyTeacher(context);
        System.out.println(notifyReturnSecond);
 
    }
}

(2)修改IocPrincipal类文件,添加输出EmailNotice和PhoneNotice实例的hashCode,用于判断程序两次从IOC容器中获取的实例是否为同一实例。

package com.milihua.springprogram.business;
import org.springframework.context.ApplicationContext;
import com.milihua.springprogram.entity.Teacher;
import com.milihua.springprogram.notice.EmailNotice;
import com.milihua.springprogram.notice.PhoneNotice;
public class IocPrincipal {
         /*
           基于Spring IOC容器的校长类,从配置文件获取通知组件
         **/
         public String  notifyTeacher(ApplicationContext ctx)
         {
                   StringBuilder  notifyReturn = new StringBuilder();
 
                   //从容器中获取通知张老师的组件
                   EmailNotice  noticeZhang = ctx.getBean("eamilNoticeZhang",EmailNotice.class);
                   //输出EmailNotice实例的hashCode
                   System.out.println("EmailNotice实例的hashCode:" + noticeZhang.hashCode());
                   noticeZhang.sendMessage();
                   //从容器中获取张老师的实例
                   Teacher  teacherZhang = ctx.getBean("teacherZhang",Teacher.class);
                   notifyReturn.append(teacherZhang.getNotify() + "<p>");
 
                   //从容器中获取通知王老师的组件
                   PhoneNotice  phoneNoticWang = ctx.getBean("phoneNoticeWang",PhoneNotice.class);
                   //输出PhoneNotice例的hashCode
                   System.out.println("PhoneNotice实例的hashCode:" + phoneNoticWang.hashCode());
 
                   phoneNoticWang.sendMessage();
                   //从容器中获取王老师的实例
                   Teacher  teacherWang = ctx.getBean("teacherWang",Teacher.class);
                   notifyReturn.append(teacherWang.getNotify() + "<p>");
 
                   //从容器中获取通知李老师的组件
                   PhoneNotice  phoneNoticLi = ctx.getBean("phoneNoticeLi",PhoneNotice.class);
                   phoneNoticLi.sendMessage();
                   //从容器中获取王老师的实例
                   Teacher  teacherLi = ctx.getBean("teacherLi",Teacher.class);
                   notifyReturn.append(teacherLi.getNotify() + "<p>");
 
                   return  notifyReturn.toString();
         }
}

(3)执行SingletonTest类文件,输出结果如下图所示。

blob.png

图1 执行SingletonTest类输出结果

从输出结果可以看出,程序两次从IOC容器中获取的EmailNotice和PhoneNotice实例的hashCode是相同的,说明IOC容器返回的是同一个实例。

三、prototype作用域

当一个Bean的作用域被定义prototype时,意味着程序每次从IOC容器获取的Bean都是一个新的实例。因此,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。

配置Bean为singleton作用域的配置代码如下。

<!-- A bean definition with singleton scope -->
<bean id="..." class="..." scope="prototype">
    <!-- collaborators and configuration for this bean go here -->
</bean>

prototype作用域示例:

(1)修改dispatcher.xml配置文件,在定义的Bean中添加prototype属性。

<?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:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context-3.2.xsd
                           http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
    <bean id="teacherZhang" class="com.milihua.springprogram.entity.Teacher">
        <property name="name" value="张老师"></property>
    </bean>
    <bean id="teacherWang" class="com.milihua.springprogram.entity.Teacher">
        <property name="name" value="王老师"></property>
    </bean>
    <bean id="teacherLi" class="com.milihua.springprogram.entity.Teacher">
        <property name="name" value="李老师"></property>
    </bean>
    <bean id="eamilNoticeZhang" scope="prototype" class="com.milihua.springprogram.notice.EmailNotice" p:teacher-ref="teacherZhang" >
        <property name="message" value="8:45上语文课"></property>
    </bean>
    <bean id="phoneNoticeWang" scope="prototype" class="com.milihua.springprogram.notice.PhoneNotice" p:teacher-ref="teacherWang">
        <property name="message" value="9:50上数学课"></property>
    </bean>
    <bean id="phoneNoticeLi" class="com.milihua.springprogram.notice.PhoneNotice" p:teacher-ref="teacherLi">
        <property name="message" value="13:50上音乐课"></property>
    </bean>
</beans>

(3)执行SingletonTest类文件,输出结果如下图所示。

blob.png

 

图2 添加prototype后执行SingletonTest类输出结果

从输出结果可以看出,程序两次从IOC容器中获取的EmailNotice和PhoneNotice实例的hashCode是不相同的,说明EmailNotice和PhoneNotice添加prototype作用域后,IOC容器每次返回的都是一个新的实例。

课程小结

Spring IOC容器创建一个Bean实例时,可以为Bean指定实例的作用域,作用域包括singleton(单例模式)、prototype(原型模式)、request(HTTP请求)、session(会话)、global-session(全局会话)。

本文重点介绍了singleton和prototype模式,这两个模式的作用域在Spring框架中是经常用到的。对于singleton作用域的Bean,IOC容器每次都返回同一个实例,而prototype作用域的Bean,IOC容器每次产生一个新的实例。

 

代码在线纠错(通义千问 qwen-max)

支持粘贴多个代码文件,提交后由阿里云通义千问自动分析代码漏洞、语法错误、逻辑问题并给出修改建议。
您已解锁 AI 代码纠错功能,可正常使用!

评论区

登录 后发表评论
暂无评论