在 Spring
中,那些组成应用程序的主体及由 Spring IOC
容器所管理的对象,被称之为 bean
。
简单地讲,bean
就是由 IOC
容器初始化、装配及管理的对象。
而作用域代表的 bean
的创建存在方式,可以在哪里使用
我们分别可以使用以下这四种情况
scope取值 | 含义 | 创建对象的时机 |
---|---|---|
singleton(默认) | 在一个IOC容器中,这个 bean对象只有一个实例 | IOC容器初始时创建单例 bean |
prototype | 在一个IOC容器中,这个 bean有多个实例 | 获取 bean的时候 |
request | 每一次 http请求,都会创建一个 bean | 每一次 http请求的时候 |
session | 同一个 http session中,有且仅有一个 bean | 产生新的 http session会话的时候 |
后面两种不做要求,仅用在基于 web
的 Spring ApplicationContext
环境
演示 singleton
和 prototype
的区别
package com.banmoon.test.scope;
import com.banmoon.test.User;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
@Configuration
public class BeanScope {
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
@Bean(name = "user")
public User user() {
return new User(1, "banmoon");
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanScope.class);
User user = context.getBean(User.class);
System.out.println(user);
System.out.println("========== 分割线 ==========");
// 再次获取user
User user1 = context.getBean(User.class);
System.out.println(user1);
}
}
单例启动,结果如下,两次对象地址打印是一致的
将 @Scope
注解的值改为 prototype
package com.banmoon.test.scope;
import com.banmoon.test.User;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
@Configuration
public class BeanScope {
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Bean(name = "user")
public User user() {
return new User(1, "banmoon");
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanScope.class);
User user = context.getBean(User.class);
System.out.println(user);
System.out.println("========== 分割线 ==========");
// 再次获取user
User user1 = context.getBean(User.class);
System.out.println(user1);
}
}
可以看到他们的地址是不一致的
还有一点,注意上面
spring
打印的debug
日志,可以清楚的看到bean
创建的时间节点, 单例bean
是在IOC
容器初始化后,马上就进行了创建 原型bean
是在每次创建时才进行创建,这也是每次获取不一致的原因所在
什么是 bean
的生命周期,就是一个 bean
从出生到死亡的过程,其中经历了哪些步骤,了解这些步骤,我们就可以更加清晰了解 bean
的运行规律。
总的来说,bean
的生命周期可以规划为下面这个步骤
set
方法进行赋值
Aware
系列接口,具体可以查看它的几个子接口具体是做什么的
InitializingBean
接口,调用其初始化方法
bean
标签中指定的初始化方法
DisposableBean
接口,调用其销毁方法
bean
标签中指定的销毁方法
package com.banmoon.test.lifecycle;
import lombok.Getter;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
/**
* @author banmoon
*/
@Getter
public class User implements InitializingBean, DisposableBean, BeanNameAware {
private String name;
public User() {
System.out.println("1、调用无参构造进行创建");
}
public void setName(String name) {
System.out.println("2、通过set方法进行设置属性");
this.name = name;
}
@Override
public void setBeanName(String s) {
System.out.println("3、Aware系列接口,处理相关的逻辑");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("4、InitializingBean接口,初始化方法");
}
public void myInit() {
System.out.println("5、在bean标签中指定的初始化方法");
}
@Override
public void destroy() throws Exception {
System.out.println("7、DisposableBean接口,销毁方法");
}
public void myDestroy() {
System.out.println("8、在bean标签中指定的销毁方法");
}
}
package com.banmoon.test.lifecycle;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
public class Main {
@Bean(name = "user", initMethod = "myInit", destroyMethod = "myDestroy")
public User user() {
User user = new User();
user.setName("user");
return user;
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Main.class);
User bean = context.getBean("user", User.class);
System.out.println("6、进行模拟使用:" + bean.getName());
context.close();
}
}
代码比较简单,直接查看运行结果