在Spring框架的学习中,控制反转(IOC)是基石。掌握了如何让Spring容器创建和管理对象后,我们需要更深入地了解容器本身、对象的生老病死,以及如何用更优雅的注解方式来简化配置。本文将带你从Spring的工厂类入手,逐步解析Bean的生命周期和作用域,并过渡到基于注解的IOP配置实践。
目录
一、Spring的工厂类:ApplicationContext 与 BeanFactory
1. ApplicationContext
2. BeanFactory
3. 核心区别与验证
二、Bean的作用域与生命周期
1. Bean的作用域(Scope)
2. Bean的生命周期
三、迈向注解:基于注解的IOC与DI配置
1. 开启注解扫描
2. 创建对象的注解(取代
)
3. 依赖注入的注解(取代
)
总结
一、Spring的工厂类:ApplicationContext 与 BeanFactory
Spring提供了两种核心的容器(工厂)接口来创建和管理Bean:ApplicationContext和 BeanFactory。它们构成了IOC容器的基础,但在行为上有显著差异。
1. ApplicationContext
ApplicationContext是 BeanFactory的子接口,提供了更多企业级功能。在创建容器时,它会立即加载并实例化所有配置的单例Bean,这种“急切加载”方式确保了应用启动后Bean立即可用。常见的实现类有:
| ClassPathXmlApplicationContext | 从类路径下加载XML配置文件。 |
| FileSystemXmlApplicationContext | 从文件系统路径加载XML配置文件 |
其类结构关系如下图所示:

2. BeanFactory
BeanFactory是Spring容器最顶层的接口,提供了IOC的基础功能。与ApplicationContext的最大区别在于它的延迟加载机制:只有在首次通过getBean()方法请求某个Bean时,容器才会创建该Bean的实例。它的一个常用实现是XmlBeanFactory(注:Spring 5.x后已不推荐使用)。
3. 核心区别与验证
我们可以通过一个简单的测试来观察二者的区别。假设我们有一个UserServiceImpl,在其无参构造方法中打印日志。
使用ApplicationContext:
public class Client {
public static void main(String[] args) {
new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("Spring IOC容器创建好了");
}
}
输出结果为:

Bean在容器初始化时就被创建。
使用BeanFactory:
public class Client {
public static void main(String[] args) {
new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
System.out.println("Spring IOC容器创建好了");
}
}
输出结果为:

此时Bean并未被创建,直到调用getBean(“userService”)时才会触发构造方法。
在实际开发中,功能更全面的ApplicationContext是更常见的选择。
二、Bean的作用域与生命周期
理解Bean何时创建、如何存在以及何时销毁,是进行高效、正确开发的关键。
1. Bean的作用域(Scope)
通过<bean>标签的scope属性,我们可以控制Bean的实例范围,常用的有以下几种:
| singleton (默认) | 在整个IOC容器中,该Bean定义只存在一个共享实例。适合无状态的Service、DAO等 |
| prototype | 每次请求该Bean时都会创建一个新的实例。适合有状态的Connection、SqlSession等对象 |
| request/session/application | 专用于Web环境,将Bean生命周期绑定到对应的Http请求、会话或应用全局 |
配置示例:<bean id="userService" class="…" scope="prototype"/>
2. Bean的生命周期
Bean从创建到销毁的完整过程,对于单例和多例模式有所不同。
单例Bean的生命周期:
[容器启动] —> 构造方法(实例化) —> set方法(依赖注入) —> init方法(自定义初始化) —> [容器关闭] —> destroy方法(自定义销毁)
多例Bean的生命周期:
[调用getBean()] —> 构造方法(实例化) —> set方法(依赖注入) —> init方法(自定义初始化) —> [JVM垃圾回收] —> destroy方法(自定义销毁) (注意:Spring容器不管理原型Bean的销毁)
我们可以通过init-method和destroy-method属性指定自定义的初始化和销毁方法,让Spring在对应时机调用。
三、迈向注解:基于注解的IOC与DI配置
XML配置功能强大但略显繁琐。Spring提供了基于注解的配置方式,其目标与XML完全一致——降低耦合,只是形式更简洁,贴近代码。
1. 开启注解扫描
首先,需要在XML配置中声明注解驱动,并指定要扫描的包。Spring会自动扫描该包及其子包下的类,识别特定注解。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
…>
<!– 开启注解扫描,base-package指定扫描的根包 –>
<context:component-scan base-package="com.hg"></context:component-scan>
</beans>
2. 创建对象的注解(取代 <bean>)
以下四个注解功能相同,都用于将类声明为Spring管理的Bean,主要提供语义化区分:
| @Component | 通用注解,用于任何组件 |
| @Controller | 通常用于标注表现层(如MVC控制器)组件 |
| @Service | 通常用于标注业务逻辑层组件 |
| @Repository | 通常用于标注数据访问层(DAO)组件 |
属性:value用于指定Bean在容器中的id。若不指定,则默认id为类名首字母小写。
//@Service("userService") 自定义id为"userService"
@Service // 默认id为"userServiceImpl"
public class UserServiceImpl implements UserService { … }
@Repository // 默认id为"userDaoImpl"
public class UserDaoImpl implements UserDao { … }
3. 依赖注入的注解(取代 <property>)
| @Autowired(Spring提供) | 默认按类型(byType)自动装配。可以与@Qualifier结合使用,实现按名称装配 |
| @Resource(JSR-250标准) | 默认按名称(byName)自动装配。可通过name属性显式指定Bean的id |
@Service
public class UserServiceImpl implements UserService {
@Autowired // 按类型查找UserDao的实现类并注入
private UserDao userDao;
// 或者
@Resource(name="userDaoImpl") // 按名称查找id为"userDaoImpl"的Bean并注入
private UserDao userDao;
…
}
| @Value | 用于注入基本数据类型和String类型的值。可以直接注入字面量,也支持从属性文件(.properties)中读取,极大提升了配置的灵活性 |
① 注入简单值:
@Service
public class UserServiceImpl implements UserService {
@Value("张三")
private String name;
@Value("25")
private Integer age;
}
② 注入属性文件中的值:
首先,在XML中加载属性文件:
<context:property-placeholder location="config.properties"/>
然后,在属性文件config.properties中定义:
jdbc.username=root
jdbc.password=123456
最后,在类中使用@Value并配合${}占位符注入:
@Service
public class UserServiceImpl implements UserService {
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
}
总结
从理解ApplicationContext和BeanFactory这两大容器的加载机制差异,到掌握Bean的singleton与prototype作用域及其完整的生命周期,是夯实Spring IOC核心概念的关键。而基于注解的配置方式(@Component, @Autowired, @Value等)则代表了更现代、更简洁的Spring开发风格,它通过将配置信息直接写在代码中,减少了XML文件的维护成本,提高了开发效率。从XML到注解,是Spring学习者必须跨越的一道桥梁。