《Spring实战 第四版》Bean

本文最后更新于 2025年9月13日 下午

在讲Spring Bean之前,我们先来讲讲简单的JavaBean

JavaBean

JavaBean简单来说就是一种符合特定规范的普通Java类:

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
public class User{
private String name;
private int age;

public User(){
}

public String getName(){
return name;
}

public void setName(String name){
this.name = name;
}

public int getAge(){
return age;
}

public void setAge(int age){
this.age = age;
}

public boolean isChild(){
return agt <= 6;
}
}

其中的核心特征有:

  • 有无参构造器
  • 字段都是私有的
  • 提供public的属性:getter/setter
    • 只有getter的属性称为只读属性
    • 只有setter的属性称为只写属性(For what?!)
  • 遵循命名规范
  • 可序列化(可选)

对于boolean字段,其读方法一般被命名为isXyz()。这里可以引出一个很经典的面试问题:

为什么boolean字段的命名通常不允许以is开头?

  • 对程序自动生成的属性来说,如果一个boolean字段以is开头,便会出现一些非常奇怪的命名isIsXyz()
  • 许多序列化的框架(Jackson, Gson等)都依赖JavaBean规范
  • 对于某些框架来说(Spring, Hibernate),使用反射访问字段时容易出现问题。

JavaBean的主要目的是为了设立一种规范以自动化地完成一系列任务。比如:

  • 数据传输,更方便序列化
  • 便于分析以自动生成属性代码
  • 轻松的图形可视化设计

在了解了JavaBean后,我们可以介绍一下Spring Bean了。

Spring Bean

Spring Bean是否Spring IoC容器创建,组装和管理的对象。也就是说,当你定义一个类时在上面加了与Spring Bean相关的注解,这个对象就会被视为是一个Spring Bean。

1
2
3
4
5
6
7
8
9
@Component
public class UserService{
@Autowired
private UserRepository userRepository;

public User findUserById(long id){
return userRepository.findById(id);
}
}

这个UserService便是一个Spring Bean,因为其被@Component注解修饰了。

当一个类成为Spring Bean,它有了如下特性:

  • 由IoC容器(Spring 容器)管理生命周期
  • 支持依赖注入
  • 支持AOP编程
  • 支持各种作用域(singleton, prototype等)

Spring容器(IoC容器)

Spring容器(IoC容器,往后我就叫IoC容器了,大伙听这个听得比较多)是Spring框架的核心。它用于创建,管理相互协作的组件之间的关联。

Spring中有多个IoC容器的实现:

  • bean工厂(org.springframework.beans.factory.beanFactory接口定义)
  • 应用上下文(org.springframework.context.ApplicationContext接口定义)

如今更多的是使用应用上下文来实现容器,但实际上,我们只要去简单地翻翻源码,便能够看见ApplicationContext是基于BeanFactory实现的。

1
2
3
4
5
6
7
// ApplicationContext的继承关系
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
//...
}
// 这里面继承了两个BeanFactory接口:ListableBeanFactory, HierarchicalBeanFactory,这两个接口都继承了BeanFactory接口。
public interface ListableBeanFactory extends BeanFactory {}
public interface HierarchicalBeanFactory extends BeanFactory {}

书中表示由于应用上下文更受欢迎,因此并没有对原始的BeanFactory做过多赘述,因此接下来将直接讲应用上下文的内容。

应用上下文 ApplicationContext

Spring中虽然有很多种应用上下文,但是最常遇到的是如下几个:

  • AnnotationConfigApplicationContext:从一个或多个基于 Java 的配置类中加载 Spring 应用上下文。
  • AnnotationConfigWebApplicationContext:从一个或多个基于 Java 的配置类中加载 Spring Web 应用上下文。
  • ClassPathXmlApplicationContext:从类路径下的一个或多个 XML 配置文件中加载上下文定义,把应用上下文的定义文件作为类资源。
    • ApplicationContext ctx = new ClassPathXmlApplicationContext("agent.xml")
  • FileSystemXmlapplicationcontext:从文件系统下的一 个或多个 XML 配置文件中加载上下文定义。
    • ApplicationContext ctx = new FileSystemXmlApplicationContext("c://agent.xml")
  • XmlWebApplicationContext:从 Web 应用下的一个或多个 XML 配置文件中加载上下文定义。

bean的生命周期

传统的JavaBean是单纯的使用new来实例化bean以进行使用。当bean不再被使用时,则由Java自动进行垃圾回收。而Spring Bean则比这个复杂多了。

这里展示一下书中给的流程图:

SpringBean生命周期流程图

  • Spring 对 bean 进行实例化;
  • Spring 将值和 bean 的引用注入到 bean 对应的属性中;
  • 如果 bean 实现了 BeanNameAware 接口,Spring 将 bean 的 ID 传递给 setBeanName()方法;
  • 如果 bean 实现了 BeanFactoryAware 接口,Spring 将调用 setBeanFactory() 方法,将 BeanFactory 容器实例传入;
  • 如果 bean 实现了 ApplicationContextAware 接口,Spring 将调用 setApplicationContext() 方法,将 bean 所在的应用上下文的引用传入进来;
  • 如果 bean 实现了 BeanPostProcessor 接口,Spring 将调用它们的 postProcessBefore-Initialization() 方法;
  • 如果 bean 实现了 InitializingBean 接口,Spring 将调用它们的 afterPropertiesSet() 方法。类似地,如果 bean 使用 initmethod 声明了初始化方法,该方法也会被调用;
  • 如果 bean 实现了 BeanPostProcessor 接口,Spring 将调用它们的 postProcessAfter-Initialization() 方法;
  • 此时,bean 已经准备就绪,可以被应用程序使用了,它们将一直驻留在应用上下文中,直到该应用上下文被销毁;
  • 如果 bean 实现了 DisposableBean 接口,Spring 将调用它的 destroy() 接口方法。

总的来说,Bean的生命周期可由以下五个步骤概括:

graph TD
	1[实例化 Instantiation] --> 2[属性赋值 Populate] --> 3[初始化 Initialization] --> 4[使用 In Use] --> 5[销毁 Destruction]

Spring会基于该bean实现的接口和bean中使用的注解来决定是否执行额外的操作:

  • @PostConstruct:如果Bean的方法上有该注解,则会在bean初始化阶段被调用
  • 自定义init-method:如果在Bean定义中指定了初始化方法,该方法也会被执行
  • @PreDestroy:如果Bean的方法上有该注解,则会在bean被销毁前调用
  • 自定义destroy-method:如果在Bean定义中指定了销毁方法,则该方法也会被执行。

我猜测这只是一小部分,实际上Spring对Bean的操作十分精密,功能繁多。一个个讲属实讲不完。

看到这里,我发现书中给的内容属实是需要结合Spring官方文档和网上大佬写的博客一起看,顺便本地还要开一个Spring项目测试下来看看到底是个什么行为。此外,Spring所蕴含的东西实在是太多了,如果跟随者教程或书籍立马写出总结的话,总会在后面再看书的时候发现自己前面写的根本就是欠妥当的,或者甚至根本就是错的。因此,接下来的章节中,我只会将在测试过程中发现的问题和具体操作过程写下来。知道真正确定自己了解了之后,才会做最终的总结。


《Spring实战 第四版》Bean
http://example.com/2025/09/12/Spring学习/《Spring实战 第四版》Bean/
作者
Clain Chen
发布于
2025年9月12日
许可协议