文章目录
- 前言
- 一、创建两个组件
- 二、使用传统方式
- 三、使用SpringBoot方法
- 四、查看是否添加到组件中
- 总结
前言
@Configuration // 告诉 SpringBoot 这是一个配置类 == 配置文件
@Bean // 给容器中添加组件。以方法名作为组件的id,返回类型就是组件类型。返回的值,就是组件在容器中的实例
@Bean("tom123") // 给容器中添加组件。以方法名作为组件的id,返回类型就是组件类型。返回的值,就是组件在容器中的实例
IOC 容器(Inversion of Control Container)是实现 控制反转 思想的一个运行期框架组件,用来集中创建、装配、管理对象(Bean)及其生命周期。
一句话:原来由程序代码 new 的对象,现在统一交给容器"注入"进来,代码只声明"我需要什么",而不关心"怎么得到"。
- 控制反转(IoC):对象创建与依赖绑定的"控制权"从业务代码反转到容器。
- 依赖注入(DI):容器把依赖对象"注入"到需要它的地方,常见方式:
- 构造函数注入
- Setter 注入
- 字段/注解注入
c
// 声明组件
@Component
public class OrderService { }
@RestController
public class OrderController {
@Autowired // 容器注入
private OrderService service;
}
启动 Spring 后,容器扫描注解 → 创建 OrderService → 注入 OrderController,全程无 new。
一、创建两个组件
我们先创建两个组件User和Pet,也就是两个类,放在bean包里面。

c
package com.hello.bean;
/**
* 用户
*/
public class User { // 要把这两个组件添加到容器中
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
// 添加带参数的构造方法
public User(String name, Integer age){
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User [name=" + name + ", age=" + age + "]";
}
}
c
package com.hello.bean;
/**
* 宠物
*/
public class Pet {
private String name;
public String getName(){
return name;
};
public void setName(String name){
this.name = name;
}
// 添加构造器
public Pet() { // 无参构造器
}
public Pet(String name) { // 带参构造器
this.name = name;
}
@Override
public String toString() {
return "Pet{" +
"name='" + name + '\'' +
'}';
}
}
二、使用传统方式
要添加到容器中,首先在资源文件夹中新建beans.xml文件,然后进行组件的添加。

源代码
c
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.hello.bean.User">
<property name="name" value="zhangsan"></property>
<property name="age" value="18"></property>
</bean>
<bean id="cat" class="com.hello.bean.Pet">
<property name="name" value="tomcat"></property>
</bean>
</beans>
解释
这个XML文件是一个典型的Spring框架配置文件,用于定义和配置Spring容器中的Bean。下面是对这个配置文件的详细解释:
-
XML声明和命名空间:
xml<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
- 第一行是标准的XML声明
- 定义了
beans
根元素和Spring的命名空间 - 指定了XML Schema定义文件的位置
-
User Bean定义:
xml<bean id="user" class="com.hello.bean.User"> <property name="name" value="zhangsan"></property> <property name="age" value="18"></property> </bean>
- 定义了一个ID为"user"的Bean
- 类路径为
com.hello.bean.User
- 设置了两个属性:
name
属性值为"zhangsan"age
属性值为18
-
Pet Bean定义:
xml<bean id="cat" class="com.hello.bean.Pet"> <property name="name" value="tomcat"></property> </bean>
- 定义了一个ID为"cat"的Bean
- 类路径为
com.hello.bean.Pet
- 设置了
name
属性值为"tomcat"
-
配置特点:
- 使用了setter注入方式(通过
<property>
元素) - 注入的都是简单值(String和int)
- 没有定义Bean之间的依赖关系
- 使用了setter注入方式(通过
-
对应的Java类结构 :
假设的User类:
javapackage com.hello.bean; public class User { private String name; private int age; // 必须有setter方法 public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } }
假设的Pet类:
javapackage com.hello.bean; public class Pet { private String name; public void setName(String name) { this.name = name; } }
-
使用场景:
- 这种配置方式在传统的Spring XML配置中很常见
- 适用于简单的Bean定义和属性注入
- 在现代Spring Boot应用中,这种配置方式通常被注解配置(如
@Component
、@Configuration
)取代
注意:要使这个配置正常工作,对应的Java类必须有无参构造函数和相应的setter方法,因为这里使用的是setter注入方式。
三、使用SpringBoot方法
新建config.MyConfig类,在其中写入代码:
源代码
c
package com.hello.config;
import com.hello.bean.User;
import com.hello.bean.Pet;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration // 告诉 SpringBoot 这是一个配置类 == 配置文件
public class MyConfig {
@Bean // 给容器中添加组件。以方法名作为组件的id,返回类型就是组件类型。返回的值,就是组件在容器中的实例
public User user01() {
return new User("zhangsan", 18);
}
@Bean // 给容器中添加组件。以方法名作为组件的id,返回类型就是组件类型。返回的值,就是组件在容器中的实例
public Pet cat(){
return new Pet("tomcat");
}
}
解释
使用 Java 配置类替代 XML 配置的 Spring Boot 配置示例,下面是对这段代码的详细解释:
- 类级别注解:
java
@Configuration // 告诉 SpringBoot 这是一个配置类 == 配置文件
public class MyConfig {
@Configuration
注解标识这是一个 Spring 配置类,相当于 XML 配置文件- 配置类中可以定义多个
@Bean
方法,用于向 Spring 容器注册组件
- User Bean 定义:
java
@Bean // 给容器中添加组件
public User user01() {
return new User("zhangsan", 18);
}
@Bean
注解表示该方法会返回一个对象,该对象要注册到 Spring 容器中- 默认情况下,Bean 的名称(ID)就是方法名
user01
- 这里创建了一个 User 对象,使用构造器注入方式设置 name="zhangsan" 和 age=18
- Pet Bean 定义:
java
@Bean // 给容器中添加组件
public Pet cat(){
return new Pet("tomcat");
}
- 同样使用
@Bean
注解,Bean 的名称为cat
- 创建了一个 Pet 对象,设置 name="tomcat"
-
与 XML 配置的对比:
- 等效于之前的 XML 配置,但使用了更现代的 Java 配置方式
- 不需要 setter 方法,直接使用构造器注入
- 类型安全,编译器可以检查类型错误
- 可以方便地添加逻辑(如条件判断等)
-
对应的 Java 类结构 :
假设的 User 类(需要对应的构造器):
java
package com.hello.bean;
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
}
假设的 Pet 类:
java
package com.hello.bean;
public class Pet {
private String name;
public Pet(String name) {
this.name = name;
}
}
-
使用特点:
- 这是 Spring Boot 推荐的首选配置方式
- 配置类本身也是一个 Spring 组件(
@Configuration
是@Component
的派生注解) - 可以方便地与其他 Spring 特性(如
@Profile
,@Conditional
等)结合使用 - 支持方法间调用(Spring 会拦截确保单例)
-
获取这些 Bean :
在应用中可以通过以下方式获取:
java
// 通过类型获取
User user = applicationContext.getBean(User.class);
// 通过名称获取
Pet pet = (Pet) applicationContext.getBean("cat");
这种基于 Java 的配置方式比 XML 更类型安全、更灵活,是现代 Spring Boot 应用的主要配置方式。
四、查看是否添加到组件中
查看
在主程序中进行容器IOC中所有组件的输出。
可以搜到对应的组件,说明组件已经添加成功。
自定义组件名
可以通过@Bean("tom123") 这样的方式自定义组件名,这样添加组件名称就是不是默认的方法名。
c
@Bean("tom123") // 给容器中添加组件。以方法名作为组件的id,返回类型就是组件类型。返回的值,就是组件在容器中的实例
public Pet cat(){
return new Pet("tomcat");
}
我们来进行组件名的输出,点启动项目。在控制台观察、搜索添加的组件。
c
public static void main(String[] args) {
// 1、返回我们IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
// 2、查看容器里面的所有组件
String[] names = run.getBeanDefinitionNames();
for (String name : names){
System.out.println(name);
}
// 3、从容器中获取组件
// 拼接最终启动成功信息
String successMessage =
"🎉 **启动成功!** (ノ◕ヮ◕)ノ*:・゚✧\n" +
"✨ *服务已就绪,端口 8083* ✨\n" +
"💻 访问地址:`http://localhost:8083`\n" +
"💪 **Go! Go! Go!** (ง •_•)ง";
System.out.println(successMessage);
}

这样我们就给容器中注入了两个组件。
配置类在容器中注册的是单实例组件
c
package com.hello.config;
import com.hello.bean.User;
import com.hello.bean.Pet;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 配置类里面使用@Bean标注在方法上给容器中添加组件,默认是单实例的
*/
@Configuration // 告诉 SpringBoot 这是一个配置类 == 配置文件
public class MyConfig {
@Bean // 给容器中添加组件。以方法名作为组件的id,返回类型就是组件类型。返回的值,就是组件在容器中的实例
public User user01() {
return new User("zhangsan", 18);
}
@Bean("tom123") // 给容器中添加组件。以方法名作为组件的id,返回类型就是组件类型。返回的值,就是组件在容器中的实例
public Pet cat(){
return new Pet("tomcat");
}
}
我们可以来读取组件对象进行验证一下。
c
// 3、从容器中获取组件
Pet tom1 = run.getBean("tom123", Pet.class);
Pet tom2 = run.getBean("tom123", Pet.class);
System.out.println("两个组件是否相同" + (tom1 == tom2));

配置类本身也是容器中的一个组件
当时一个类名上加了@Configuratio以后,这个类也会被加入到容器中,作为一个组件。
验证:
c
MyConfig bean = run.getBean(MyConfig.class);
System.out.println(bean);

Configuration的proxyBeanMethods属性:代理bean的方法
应用场景:解决组件依赖问题。
c
* 3、proxyBeanMethods:代理bean的方法
* full: 全量模式,IOC容器启动时,会创建所有的单实例Bean(true)
* light: 轻量模式,IOC容器启动时,不会创建单实例Bean,而是当调用getBean方法时,才会创建Bean(false)
proxyBeanMethods
参数详解
proxyBeanMethods
是 @Configuration
注解中的一个重要属性,它决定了配置类中 @Bean
方法是否被代理。下面是它的取值含义表格:
值 | 含义 | 适用场景 | 性能影响 | 容器行为 |
---|---|---|---|---|
true (默认值) |
启用代理,确保 @Bean 方法调用总是返回相同的实例(单例) |
需要保证单例的场景,方法间有依赖关系时 | 有轻微性能开销(CGLIB代理) | Spring会拦截方法调用,检查容器中是否已存在该Bean |
false |
禁用代理,直接调用方法 | 不需要方法间依赖,或追求启动速度的场景 | 无代理开销,启动更快 | 每次调用方法都会真正执行,不保证单例 |
详细说明
1. proxyBeanMethods = true
(默认)
java
@Configuration(proxyBeanMethods = true)
public class MyConfig {
@Bean
public User user() {
return new User(pet()); // 无论调用多少次,返回的都是同一个Pet实例
}
@Bean
public Pet pet() {
return new Pet("tomcat");
}
}
- 特点:方法间调用会被Spring拦截,确保单例
- 优点:保证Bean的单例性,方法间依赖安全
- 缺点:有CGLIB代理开销
2. proxyBeanMethods = false
java
@Configuration(proxyBeanMethods = false)
public class MyConfig {
@Bean
public User user() {
return new User(pet()); // 每次调用都会new新的Pet实例
}
@Bean
public Pet pet() {
return new Pet("tomcat");
}
}
- 特点:相当于普通Java方法调用
- 优点:无代理开销,启动更快
- 缺点:不能保证方法间调用的单例性
选择建议
考虑因素 | 推荐设置 |
---|---|
配置类中的@Bean 方法需要相互调用 |
true |
需要严格的单例保证 | true |
追求应用启动速度 | false |
配置类中没有方法间调用 | false |
Spring Boot 2.2+ 的@Configuration 类 |
通常设为false |
在Spring Boot 2.2+中,很多场景下推荐使用proxyBeanMethods = false
以提高性能,特别是大型应用。
总结
本文全面对比了Spring Boot中两种主要的组件配置方式:传统XML配置和现代Java配置类方式,并深入分析了@Configuration
和@Bean
注解的核心特性。
-
配置方式演进
- XML配置是传统Spring的经典方式,通过
<bean>
标签定义组件,依赖setter注入 - Java配置类是现代Spring Boot推荐方式,使用
@Configuration
和@Bean
注解,更类型安全灵活
- XML配置是传统Spring的经典方式,通过
-
注解核心功能
@Configuration
标记配置类,替代XML配置文件@Bean
注解方法向容器注册组件,默认单例,方法名作为组件ID- 支持自定义组件名(
@Bean("name")
)和方法间依赖调用
-
高级特性
proxyBeanMethods
参数控制代理行为,平衡单例保证与性能- 配置类本身也是容器组件,可通过上下文获取
- 与各种条件注解(
@Conditional
等)无缝集成
-
实践建议
- 新项目优先使用Java配置类方式
- 简单场景可设置
proxyBeanMethods=false
提升性能 - 需要严格单例和方法间依赖时保持默认
true
值 - 合理命名组件ID提高可读性
现代Spring Boot应用开发中,基于注解的配置方式凭借其类型安全、代码导航方便和与Java语言的天然契合等优势,已成为事实标准。理解这些核心配置机制,是掌握Spring Boot自动配置原理的基础,也是进行高效应用开发的关键。