第四章:Spring Bean基础

定义 Spring Bean

什么是 BeanDefinition?

BeanDefinition 是 Spring Framework 中定义 Bean 的配置元信息接口,包含:

  • Bean 的类名
  • Bean 行为配置元素,如作用域、自动绑定的模式,生命周期回调等
  • 其他 Bean 引用,又可称作合作者(collaborators)或者依赖(dependencies)
  • 配置设置,比如 Bean

BeanDefinition元信息

image-20211219210218050

BeanDefinition 构建

通过 BeanDefinitionBuilder

1
2
3
4
5
6
7
8
9
10
11
public static void createByBeanDefinitionBuilder(){
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
// 设置属性
beanDefinitionBuilder
.addPropertyValue("id",1L)
.addPropertyValue("name","kesen");
// 获取BeanDefinition
BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
// BeanDefinition并非终态 仍然可以修改
beanDefinition.setLazyInit(false);
}

通过 AbstractBeanDefinition 以及派生类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 通过{@link AbstractBeanDefinition}及其派生类构建
*
* @see AbstractBeanDefinition
*/
public static void createByAbstractBeanDefinition(){
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
// 设置Bean 类型
genericBeanDefinition.setBeanClass(SuperUser.class);
// 设置属性
MutablePropertyValues mutablePropertyValues = new MutablePropertyValues();
mutablePropertyValues
.add("id",1L)
.add("name","kesen")
.add("address","Chengdu");
genericBeanDefinition.setPropertyValues(mutablePropertyValues);
}

命名 Spring Bean

  • Bean 的名称 每个 Bean 拥有一个或多个标识符(identifiers),这些标识符在 Bean 所在的容器必须是 唯一的。通常,一个 Bean 仅有一个标识符,如果需要额外的,可考虑使用别名(Alias)来 扩充。
  • 在基于 XML 的配置元信息中,开发人员可用 id 或者 name 属性来规定 Bean 的 标识符。
  • 通 常 Bean 的 标识符由字母组成,允许出现特殊字符。如果要想引入 Bean 的别名的话,可在 name 属性使用半角逗号(“,”)或分号(“;”) 来间隔。 Bean 的 id 或 name 属性并非必须制定,如果留空的话,容器会为 Bean 自动生成一个唯一 的名称。Bean 的命名尽管没有限制,不过官方建议采用驼峰的方式,更符合 Java 的命名约 定
  • Bean 名称生成器(BeanNameGenerator)
  • 由 Spring Framework 2.0.3 引入,框架內建两种实现: DefaultBeanNameGenerator:默认通用 BeanNameGenerator 实现
  • AnnotationBeanNameGenerator:基于注解扫描的 BeanNameGenerator 实现,起始于 Spring Framework 2.5,关联的官方文档:

Spring Bean 的别名

Bean 别名(Alias)的价值

  • 复用现有的 BeanDefinition
  • 更具有场景化的命名方法,比如:
1
2
3
4
5
6
7
8
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("classpath:META-INF/bean-definition-context.xml");
// 通过id获取User
User user = context.getBean("user", User.class);
// 通过别名获取User
User normalUser = context.getBean("commonUser", User.class);
// true
System.out.println(user == normalUser);

注册 Spring Bean

BeanDefinition 注册

XML 配置元信息
  • <bean name=”…” … />
Java 注解配置元信息
  • @Bean
  • @Component + @ComponentScan
  • @Import
Java API 配置元信息
  • 命名方式:BeanDefinitionRegistry#registerBeanDefinition(String,BeanDefinition)
  • 非命名方式: BeanDefinitionReaderUtils#registerWithGeneratedName(AbstractBeanDefinition,BeanDefinitionRegistry)
  • 配置类方式:AnnotatedBeanDefinitionReader#register(Class…)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// 通过Import
@Import(AnnotationBeanDefinitionDemo.Config.class)
public class AnnotationBeanDefinitionDemo {

public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// 配置类方式注册Bean
context.register(Config.class);

context.refresh();

// Java API 命名方式
registerUserBeanDefinition(context, "specialUser");
// Java API 非命名方式,使用类的全限定名
registerUserBeanDefinition(context);

System.out.println("Config Beans:" + context.getBeansOfType(Config.class));
System.out.println("User Beans:" + context.getBeansOfType(User.class));

// 获取别名
String[] users = context.getAliases("user");
System.out.println(Arrays.toString(users));

// 显示关闭Spring上下文
context.close();
}

private static void registerUserBeanDefinition(BeanDefinitionRegistry registry) {
registerUserBeanDefinition(registry, null);
}

private static void registerUserBeanDefinition(BeanDefinitionRegistry registry, String beanName) {
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
// 设置属性
beanDefinitionBuilder
.addPropertyValue("id", 2)
.addPropertyValue("name", "Tom");

AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
if (StringUtils.hasText(beanName)) {
registry.registerBeanDefinition(beanName, beanDefinition);
} else {
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);
}
}

// 通过@Component方式
@Component
public static class Config {

/**
* user 是 id,cruise 是别名
* 通过@Bean
* @return
*/
@Bean({"user", "cruise"})
public User user() {
User user = new User();
user.setId(1L);
user.setName("Cruise");
return user;
}
}
外部单例对象注册
  • SingletonBeanRegistry#registerSingleton
1
2
3
4
5
6
7
8
9
10
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// AnnotationConfigApplicationContext 就是 SingletonBeanRegistry 类型
beanFactory.registerSingleton("admin",new User());

User user = context.getBean("user", User.class);
System.out.println(user);

context.close();

实例化Spring Bean

image-20211219220659304

静态工厂方法

1
2
3
<!-- 静态方法实例化 Bean -->
<bean id="user-by-static-method" class="com.cruise.thinking.in.spring.ioc.container.overview.domain.User"
factory-method="createUser"/>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class User {

private Long id;
private String name;

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;
}

@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}

public static User createUser(){
User user = new User();
user.setId(1L);
user.setName("Cruise");
return user;
}
}

Bean工厂

1
2
3
4
<!-- Bean 工厂实例化 Bean  -->
<bean id="user-by-instance-method" factory-bean="userFactory" factory-method="createUser"/>
<bean id="userFactory" class="com.cruise.thinking.in.spring.bean.definition.factory.DefaultUserFactory"/>

抽象工厂

1
2
3
4
5
public interface UserFactory {
default User createUser() {
return User.createUser();
}
}

工厂实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

public class DefaultUserFactory implements UserFactory, InitializingBean, DisposableBean {

@PostConstruct
public void postConstruct() {
System.out.println("PostConstruct");
}

public void myInit(){
System.out.println("myInit");
}

@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean#afterPropertiesSet");
}

@PreDestroy
public void preDestroy(){
System.out.println("PreDestroy");
}

@Override
public void destroy() throws Exception {
System.out.println("DisposableBean#destroy");
}

public void myDestroy(){
System.out.println("myDestroy");
}

@Override
protected void finalize() throws Throwable {
System.out.println("finalize");
}
}

FactoryBean

1
2
<!-- FactoryBean实例化Bean  -->
<bean id="user-by-factory-bean" class="com.cruise.thinking.in.spring.bean.definition.factory.UserFactoryBean"/>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class UserFactoryBean implements FactoryBean<User> {

@Override
public User getObject() throws Exception {
return User.createUser();
}

@Override
public Class<?> getObjectType() {
return User.class;
}

/**
* 是否是单例 Bean
*
* @return true 会缓存第一次获取的 Bean,false 每次调 {@link #getObject()} 方法都会返回一个新的 Bean
*/
@Override
public boolean isSingleton() {
return false;
}
}

初始化Spring Bean

image-20211219222449138

1
2
3
4
5
6
7
8
9
10
// 1自定义
@Bean(initMethod = "myInit")
public UserFactory userFactory() {
return new DefaultUserFactory();
}

// 2使用AbstractBeanDefinition#setInitMethodName自定义初始化方法
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Student.class)
.setInitMethodName("initStudent").getBeanDefinition();
context.registerBeanDefinition("student",beanDefinition);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class DefaultUserFactory implements UserFactory, InitializingBean, DisposableBean {

// @PostConstruct
@PostConstruct
public void postConstruct() {
System.out.println("PostConstruct");
}

// 自定义
public void myInit(){
System.out.println("myInit");
}

// afterPropertiesSet
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean#afterPropertiesSet");
}

@PreDestroy
public void preDestroy(){
System.out.println("PreDestroy");
}

@Override
public void destroy() throws Exception {
System.out.println("DisposableBean#destroy");
}

public void myDestroy(){
System.out.println("myDestroy");
}

@Override
protected void finalize() throws Throwable {
System.out.println("finalize");
}

顺序:

PostConstruct
InitializingBean#afterPropertiesSet
myIni

延迟初始化 Spring Bean

Bean 延迟初始化(Lazy Initialization)

  • XML 配置:<bean lazy-init=”true” … />
  • Java 注解:@Lazy(true)

思考:当某个 Bean 定义为延迟初始化,那么,Spring 容器返回的对象与非延迟的对象存在怎样的差异?

生命周期

销毁 Spring Bean

Bean 销毁(Destroy)

  • @PreDestroy 标注方法

    1
    2
    3
    4
    @PreDestroy
    public void preDestroy(){
    System.out.println("PreDestroy");
    }
  • 实现 DisposableBean 接口的 destroy() 方法

    image-20211219224923087

       
    1
    2
    3
    4
    5
             
    @Override
    public void destroy() throws Exception {
    System.out.println("DisposableBean#destroy");
    }
  • 自定义销毁方法
  1. ​ XML 配置: <bean destroy=”destroy” … />
  2. ​ Java 注解:@Bean(destroy=”destroy”)
  3. ​ Java API:AbstractBeanDefinition#setDestroyMethodName(String)

思考:假设以上三种方式均在同一 Bean 中定义,那么这些方法的执行顺序是怎样

顺序

PreDestroy
DisposableBean#destroy
myDestroy

1
2
3
System.out.println("Spring上下文准备关闭");
context.close();
System.out.println("Spring上下文已经关闭");
1
2
3
4
5
Spring上下文准备关闭
PreDestroy
DisposableBean#destroy
myDestroy
Spring上下文已经关闭

垃圾回收 Spring Bean

Bean 垃圾回收(GC)

  1. 关闭 Spring 容器(应用上下文)
  2. 执行 GC
  3. Spring Bean 覆盖的 finalize() 方法被回
1
2
3
4
5
6
7
8
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanDestroyDemo.class);
System.out.println(context.getBean(UserFactory.class));
context.close();
System.out.println("Spring上下文关闭了");

Thread.sleep(2000);
// 是可以被GC的
System.gc();