Spring 将对象注册到 IOC 容器的 6 种方式
·
欢迎关注微信公众号 「思客潘」
Spring 框架:将对象注册到 IOC 容器的 6 种方式详解与实践案例
一、概述
在 Spring 框架中,IOC(Inversion of Control,控制反转) 是其核心思想,而 Bean 是 Spring 管理的基本单元。将一个普通 Java 对象(POJO)交由 Spring 容器管理,意味着该对象的创建、初始化、依赖注入和销毁均由 Spring 容器负责,开发者无需手动 new 实例。
本文将系统性地介绍 6 种将对象注册到 Spring 容器的方式,从基础注解到高级编程式注册,结合具体代码案例,帮助开发者根据实际场景选择最合适的方案。
二、方式一:@ComponentScan + @Component(注解扫描方式)
1. 原理说明
- 使用
@Component注解标记类,表示该类是一个 Spring 管理的组件。 - 使用
@ComponentScan注解指定扫描的包路径,Spring 启动时会自动发现并注册所有被@Component及其衍生注解标记的类。
2. 注解说明
@Component:通用组件注解。@Service、@Repository、@Controller:分别是@Component的语义化衍生注解,分别用于业务层、数据层和控制层。
3. 案例代码
// 1. 定义一个服务类,使用 @Service 标记
@Service
public class UserService {
public void sayHello() {
System.out.println("Hello from UserService!");
}
}
// 2. 配置类启用组件扫描
@Configuration
@ComponentScan(basePackages = "com.example.service") // 指定扫描路径
public class AppConfig {
}
// 3. 测试
public class Application {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = context.getBean(UserService.class);
userService.sayHello(); // 输出:Hello from UserService!
}
}
4. 适用场景
- 普通业务类、工具类等项目内部组件。
- Spring Boot 项目中,
@SpringBootApplication注解已包含@ComponentScan,无需额外配置。
三、方式二:@Configuration + @Bean(配置类方式)
1. 原理说明
- 使用
@Configuration注解标记一个配置类。 - 在该类中定义
@Bean注解的方法,方法返回的对象将被注册为 Spring 容器中的 Bean。
2. 案例代码
// 定义一个第三方类(无法修改源码)
public class ThirdPartyService {
public void doWork() {
System.out.println("Third party service is working.");
}
}
// 配置类中手动注册
@Configuration
public class AppConfig {
@Bean
public ThirdPartyService thirdPartyService() {
return new ThirdPartyService();
}
}
// 测试
public class Application {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
ThirdPartyService service = context.getBean(ThirdPartyService.class);
service.doWork();
}
}
3. 适用场景
- 引入第三方 JAR 包中的类(如
DataSource、RedisTemplate)。 - 需要自定义初始化逻辑的 Bean(如设置属性、条件判断等)。
四、方式三:@Import 注解(快速导入)
1. 原理说明
@Import可以直接将指定的类注册为 Bean,无需@Component。- 支持导入普通类、配置类(
@Configuration)、或实现ImportSelector/ImportBeanDefinitionRegistrar的选择器。
2. 案例代码
方式 1:直接导入类
@Import(UserService.class) // 直接注册 UserService
public class AppConfig {
}
方式 2:导入配置类
@Configuration
public class DatabaseConfig {
@Bean
public DataSource dataSource() {
return new HikariDataSource();
}
}
@Import(DatabaseConfig.class) // 导入整个配置类
public class AppConfig {
}
3. 适用场景
- 模块化开发中聚合多个配置。
- Spring Boot 自动配置(
spring.factories+@EnableAutoConfiguration)底层机制。
五、方式四:FactoryBean 接口(工厂方式)
1. 原理说明
- 实现
FactoryBean<T>接口,通过getObject()方法返回真正的 Bean 实例。 - Spring 容器会自动调用该方法,并将返回对象注册为 Bean。
2. 案例代码
public class Person {
private String name;
// getter/setter
}
public class PersonFactoryBean implements FactoryBean<Person> {
@Override
public Person getObject() {
Person person = new Person();
person.setName("Factory Created Person");
return person;
}
@Override
public Class<?> getObjectType() {
return Person.class;
}
}
@Configuration
public class AppConfig {
@Bean
public PersonFactoryBean personFactoryBean() {
return new PersonFactoryBean();
}
}
// 测试:获取的是 Person 对象,而非 PersonFactoryBean
Person person = context.getBean(Person.class);
System.out.println(person.getName()); // 输出:Factory Created Person
3. 适用场景
- MyBatis 的
SqlSessionFactoryBean。 - 需要复杂初始化逻辑或代理对象的场景。
六、方式五:编程式注册(运行时动态注册)
1. 原理说明
- 通过
BeanDefinitionRegistry或ApplicationContext在运行时动态注册 Bean。
2. 案例代码
public class DynamicBeanRegister {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// 获取注册器
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) context.getBeanFactory();
// 创建 Bean 定义
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(UserService.class);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
// 注册到容器
registry.registerBeanDefinition("userService", beanDefinition);
// 刷新容器
context.refresh();
// 获取 Bean
UserService userService = context.getBean(UserService.class);
userService.sayHello();
}
}
3. 适用场景
- 插件化系统、动态加载模块。
- 单元测试中模拟 Bean 注入。
七、方式六:XML 配置方式(传统方式)
1. 案例代码
<!-- applicationContext.xml -->
<beans>
<bean id="userService" class="com.example.UserService" />
</beans>
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) context.getBean("userService");
2. 说明
- 已被注解方式取代,仅用于维护老项目。
八、总结与选型建议
| 方式 | 适用场景 | 推荐度 |
|---|---|---|
| @Component + @ComponentScan | 项目内部普通组件 | ⭐⭐⭐⭐⭐ |
| @Configuration + @Bean | 第三方类、自定义初始化 | ⭐⭐⭐⭐⭐ |
| @Import | 模块聚合、自动配置 | ⭐⭐⭐⭐☆ |
| FactoryBean | 复杂对象、代理、框架开发 | ⭐⭐⭐⭐☆ |
| 编程式注册 | 动态加载、插件系统 | ⭐⭐⭐☆☆ |
| XML 配置 | 老项目维护 | ⭐☆☆☆☆ |
九、附录:Bean 作用域说明
| 作用域 | 说明 |
|---|---|
singleton |
单例(默认),容器中唯一实例 |
prototype |
多例,每次获取都创建新实例 |
request |
每个 HTTP 请求创建一个实例 |
session |
每个 HTTP 会话创建一个实例 |
提示:可通过 @Scope("prototype") 注解设置。
更多推荐




所有评论(0)