1、Bean 的作用域介绍
默认情况下,Spring 只为每个在 IOC 容器里声明的 Bean 创建唯一 一个实例,并且整个 IOC 容器范围内都能共享该实例,所有后续的对象通过getBean() 调用和 Bean 的引用都将返回这个唯一的 Bean 实例。但是如果我们需要不同实例的Bean呢?这时就要提到Bean的作用域了,在Spring中默认的作用域为 Singleton,它是所有 Bean 的默认作用域。而在Spring 中提供了 5 种作用域,它会根据情况来决定是否生成新的对象,如下:
- singleton:单例模式,这是 Bean 默认的作用域,使用 singleton 定义的 Bean 在整个 Spring 容器生命周期内只创建这一个 Bean。
- prototype:原型模式(多例模式),Spring 容器初始化时不创建 Bean 的实例,而在每次通过getBean获取Bean时都创建一个新的Bean实例并返回。
- request:请求模式,用于Web开发,在一次 HTTP 请求中,容器会返回该 Bean 的同一个实例。而对不同的 HTTP 请求,会返回不同的实例,该作用域仅在当前 HTTP Request 内有效。
- session:会话模式,用于Web开发,在一次 HTTP Session 中,容器会返回该 Bean 的同一个实例。而对不同的 HTTP 请求,会返回不同的实例,该作用域仅在当前 HTTP Session 内有效。
global Session(Spring5已经去除了):全局会话模式,在一个全局的 HTTP Session 中,容器会返回该 Bean 的同一个实例。该作用域仅在使用 portlet context 时有效。一般用于 Porlet 应用环境 , 分布式系统存在全局 session 概念(单点登录),如果不是 porlet 环境,globalSession 等同于 Session。
=====================================
我们可以通过XML<bean> 元素中的 scope 属性 或者 @Scope 注解 来设置Bean的作用域,例如:
- XML 中设置作用域:<bean id="" class="" scope="prototype" />
- 注解设置作用域: @Scope("prototype") 或者 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
在上述五种作用域中,实际开发中 singleton 和 prototype 是最常用的两种。
2、XML配置举例
①、首先创建一个User类,代码如下:
/** * 用户实体类 */ public class User { private int userId; private String userName; private int userAge; private String userPwd; private String userAddress; //getter、setter省略...(这里就不要toString方法了,因为要打印对象的地址) }
②、在 Spring 的配置文件我们将 scope 属性的值设置为 prototype 多例模式,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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--创建一个User实例,作用域设置为prototype 多例模式--> <bean id="user" class="com.thr.pojo.User" scope="prototype"/> </beans>
③、测试代码,这里分别获取了三个User对象:
/** * 测试代码 */ public class SpringTest { public static void main(String[] args) { //1.初始化Spring容器,加载配置文件 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); //2.通过容器获取实例 User user1 = applicationContext.getBean("user", User.class); User user2 = applicationContext.getBean("user", User.class); User user3 = applicationContext.getBean("user", User.class); //3.调用实例中的属性 System.out.println(user1); System.out.println(user2); System.out.println(user3); } }
④、运行测试代码,查看控制台打印的结果:
可以很明显的发现,这三个User对象的地址是不一样的,说明分别创建了三个不同的User对象。
3、注解配置举例
①、首先创建一个User类,代码参考上面的。
②、创建PojoConfig类,用来启动容器和注册Bean对象:
/** * 启动容器和注册Bean对象 */ @ComponentScan(basePackages = "com.thr.pojo") @Configuration public class PojoConfig { public PojoConfig() { System.out.println("PojoConfig容器初始化成功..."); } //实例化User对象 @Bean(name = "user") //显示设置单例模式 @Scope(value = "singleton") public User user(){ return new User(); } }
③、测试代码,这里分别获取了三个User对象,注意这里需要使用AnnotationConfigApplicationContext类来获取:
/** * 测试代码 */ public class SpringTest1 { public static void main(String[] args) { //1.初始化Spring容器,通过注解加载 ApplicationContext applicationContext = new AnnotationConfigApplicationContext(PojoConfig.class); //2.通过容器获取实例 User user1 = applicationContext.getBean("user", User.class); User user2 = applicationContext.getBean("user", User.class); User user3 = applicationContext.getBean("user", User.class); //3.调用实例中的属性 System.out.println(user1); System.out.println(user2); System.out.println(user3); } }
④、运行测试代码,查看控制台打印的结果:
由于注册 Bean 时Scope设置为 singleton 单例模式,所以创建的多个 User 肯定是同一个,可以发现结果是一样的。