Spring依赖注入与自动装配解析

写在前面

如果你想深入学习SpringBoot的自动配置原理,那么本文是你必须掌握的基础知识。很多人在使用SpringBoot时,只知道用@Autowired注入依赖,却不知道背后的原理。

本文将从最基础的概念讲起,带你彻底理解Spring的依赖注入机制。无论你是刚接触Spring的新手,还是想复习巩固的老手,都能从本文获益。

适合人群: Spring初学者、准备深入学习SpringBoot的开发者、需要复习基础的工程师

一、核心概念:什么是Bean、依赖和注入

在学习依赖注入之前,我们必须先理解三个基本概念。

1.1 什么是Bean?

Bean就是由Spring容器管理的对象。

在传统Java开发中,我们这样创建对象:

UserService userService = new UserService();

而在Spring中,我们不需要自己new对象,而是让Spring容器帮我们创建和管理:

@Service  // 告诉Spring:这是一个Bean,请帮我管理。@Service是@Component的衍生注解
public class UserService {
// ...
}

形象的比喻:

  • 传统方式:你需要什么对象,自己new一个(自己做饭)
  • Spring方式:你告诉Spring需要什么,Spring给你创建好(外卖送餐)

Bean的特点:

  • 由Spring容器创建
  • 由Spring容器管理生命周期
  • 默认是单例的(整个应用只有一个实例)
  • 可以被其他Bean引用

1.2 什么是依赖?

依赖就是一个对象需要使用另一个对象来完成工作。

举个例子:

public class UserService {
private UserDao userDao;  // UserService依赖UserDao
public User getUser(Long id) {
return userDao.findById(id);  // 需要用到UserDao
}
}

在这个例子中:

  • UserService 需要 UserDao 才能完成查询用户的功能
  • 我们说:UserService 依赖 UserDao

生活中的例子:

  • 你要开车上班,你依赖汽车
  • 你要做饭,你依赖厨具
  • 你要写代码,你依赖电脑

1.3 什么是注入依赖?

注入依赖就是把一个对象需要的其他对象"送"给它。

传统方式(自己创建依赖):

public class UserService {
private UserDao userDao;
public UserService() {
this.userDao = new UserDaoImpl();  // 自己创建依赖
}
}

依赖注入方式(Spring帮你注入):

@Service
public class UserService {
@Autowired  // 告诉Spring:请把UserDao注入给我
private UserDao userDao;
}

形象的比喻:

  • 传统方式:你要喝咖啡,自己买豆子、磨豆、煮咖啡(自己创建依赖)
  • 依赖注入:你要喝咖啡,告诉咖啡店,咖啡店做好送给你(Spring注入依赖)

依赖注入的好处:

  1. 解耦:UserService不需要知道UserDao的具体实现
  2. 易测试:可以轻松替换为Mock对象进行测试
  3. 易维护:要换实现,不需要修改UserService代码
  4. 统一管理:所有对象由Spring容器统一创建和管理

二、控制反转(IoC):理解Spring的核心思想

2.1 什么是控制反转?

控制反转(Inversion of Control,IoC)是一种设计思想:把对象创建和管理的控制权交给框架。

简单来说:就相当于框架帮你创建对象,只创建一次,那个类调用就把对象注入给谁

好处

  1. 彻底解放双手:不用再手动new对象、手动传依赖
  2. 统一管理对象:单例复用 + 生命周期全托管
  • 单例复用:框架创建的 Bean 默认是单例(只创建 1 次),所有需要这个对象的类,注入的都是同一个实例,避免重复创建对象浪费内存(比如一个UserDao对象,所有Service都用同一个,不用每次都new);
  • 生命周期托管:对象的 “创建→初始化→使用→销毁” 全由框架控制,你可以通过注解(如@PostConstruct初始化、@PreDestroy销毁)自定义流程,不用手动管理对象的生灭。
  1. 降低代码耦合:类之间解耦,项目易维护、易扩展

传统方式: 你控制一切

public class UserService {
private UserDao userDao;
public UserService() {
// 你决定创建什么对象
this.userDao = new UserDaoImpl();
}
}

IoC方式: Spring控制一切

@Service
public class UserService {
@Autowired
private UserDao userDao;  // Spring决定注入什么对象
}

"反转"体现在哪里?

维度传统方式IoC方式
谁创建对象你自己newSpring容器创建
谁管理对象你自己管理Spring容器管理
谁决定依赖你在代码中写死Spring根据配置决定

核心思想: 不要打电话给我们,我们会打电话给你(Don’t call us, we’ll call you)

2.2 IoC容器的作用

Spring的IoC容器(ApplicationContext)就像一个对象工厂,负责:

  1. 创建对象:根据配置创建Bean
  2. 管理生命周期:从创建到销毁
  3. 注入依赖:自动装配Bean之间的依赖关系
  4. 提供服务:提供Bean的查找、获取等功能
// Spring容器启动时
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 从容器获取Bean
UserService userService = context.getBean(UserService.class);
// 这个userService已经注入好了所有依赖,可以直接使用
User user = userService.getUser(1L);

三、依赖注入的三种方式

Spring支持三种依赖注入方式,每种都有各自的适用场景。

方式1:字段注入(最常见但不推荐)

@Service
public class UserService {
@Autowired
private UserDao userDao;
@Autowired
private EmailService emailService;
}

优点: 代码简洁,写起来方便

缺点:

  • 无法注入final字段(不能保证不可变性)
  • 不利于单元测试(必须启动Spring容器或使用反射)
  • 违反了面向对象的封装原则
  • 依赖关系不明确

方式2:构造器注入(强烈推荐)

@Service
//@RequiredArgsConstructor      
//Lombok注解,写了这个就不用写构造器了,但是要加入Lombok依赖。(依赖在博主之前的关于Lombok的文章中有提到过)
public class UserService {
private final UserDao userDao;
private final EmailService emailService;
// Spring 4.3+ 单构造器可省略@Autowired
public UserService(UserDao userDao, EmailService emailService) {
this.userDao = userDao;
this.emailService = emailService;
}
}

优点:

  • 可以使用final,保证不可变性和线程安全
  • 便于单元测试(直接new对象传参,无需Spring容器)
  • 依赖关系一目了然
  • 如果依赖过多,构造器参数会很长,提醒你类职责可能过重

这是Spring官方推荐的方式!

方式3:Setter方法注入

@Service
public class UserService {
private UserDao userDao;
@Autowired
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}

优点: 可以在对象创建后重新注入依赖(适合可选依赖)

缺点: 依赖可能为null,不够安全

三种方式对比:

特性字段注入构造器注入Setter注入
代码简洁度最简洁中等较繁琐
是否支持final
测试友好度中等
依赖明确度不明确非常明确较明确
官方推荐度不推荐强烈推荐适合可选依赖

四、@Autowired与自动装配详解

4.1 什么是自动装配?

自动装配(Auto-Wiring)是Spring自动为Bean注入依赖的机制。

简单来说:你只需要告诉Spring"我需要这个依赖"(通过@Autowired注解),Spring会自动帮你找到合适的Bean并注入进来。

传统方式(手动装配):

<bean id="userDao" class="com.example.dao.UserDaoImpl"/>
  <bean id="userService" class="com.example.service.UserService">
  <property name="userDao" ref="userDao"/>  <!-- 手动指定依赖 -->
</bean>

自动装配方式:

@Service
public class UserService {
@Autowired  // 自动装配,Spring自动找到UserDao并注入
private UserDao userDao;
}

4.2 自动装配的演进历史

阶段1:XML时代(Spring 1.x - 2.x)

<!-- 按类型自动装配 -->
    <bean id="userService" class="com.example.service.UserService"
    autowire="byType"/>
  <!-- 按名称自动装配 -->
      <bean id="userService" class="com.example.service.UserService"
      autowire="byName"/>

阶段2:注解时代(Spring 2.5+)

@Service
public class UserService {
@Autowired  // 注解方式,更简洁
private UserDao userDao;
}

阶段3:纯Java配置时代(Spring 3.0+)

Spring 3.0 引入了 @Configuration@Bean

@Configuration
public class AppConfig {
@Bean
public UserDao userDao() {
return new UserDaoImpl();
}
@Bean
public UserService userService() {
return new UserService();  // 自动装配
}
}

阶段4:SpringBoot时代(Spring 4.0+)

@SpringBootApplication  // 自动扫描,自动装配
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

4.3 自动装配的工作原理

核心处理器:AutowiredAnnotationBeanPostProcessor

完整流程:

1. Spring容器启动,扫描所有Bean定义
   ↓
2. 创建Bean实例(调用构造函数)
   ↓
3. AutowiredAnnotationBeanPostProcessor介入
   ↓
4. 扫描Bean中的@Autowired注解
   ↓
5. 解析依赖类型
   ↓
6. 在容器中查找匹配的Bean
   ├─ 按类型查找(byType)- 默认策略
   ├─ 如果有多个,按@Primary筛选
   ├─ 如果还有多个,按@Qualifier筛选
   └─ 如果还有多个,按字段名称匹配
   ↓
7. 通过反射注入依赖
   ↓
8. Bean初始化完成

4.4 自动装配的匹配策略

策略1:按类型匹配(byType)- 默认

@Service
public class UserService {
@Autowired
private UserDao userDao;  // 查找UserDao类型的Bean
}
  • 找到1个 → 直接注入
  • 找到0个 → 抛出异常(除非required=false)
  • 找到多个 → 继续下一步匹配

策略2:按@Primary匹配 - 优先级

@Repository
@Primary  // 标记为首选
public class UserDaoMysqlImpl implements UserDao { }
@Repository
public class UserDaoMongoImpl implements UserDao { }
@Service
public class UserService {
@Autowired
private UserDao userDao;  // 自动选择@Primary标记的Bean
}

策略3:按@Qualifier匹配 - 明确指定

@Service
public class UserService {
@Autowired
@Qualifier("userDaoMongoImpl")  // 明确指定使用哪个Bean
private UserDao userDao;
}

策略4:按字段名称匹配 - 辅助

@Service
public class UserService {
@Autowired
private UserDao userDaoMysqlImpl;  // 字段名与Bean名称一致
}

策略5:注入集合 - 获取所有实现

@Service
public class UserService {
// 注入所有UserDao类型的Bean
@Autowired
private List<UserDao> userDaoList;
  // 注入所有UserDao类型的Bean到Map,key为Bean名称
  @Autowired
  private Map<String, UserDao> userDaoMap;
    }

匹配优先级:

@Qualifier(最高优先级)
    ↓
@Primary
    ↓
字段名称匹配
    ↓
类型匹配(默认)

4.5 处理多个候选Bean

当容器中有多个相同类型的Bean时:

// 有两个UserDao的实现
@Repository
public class UserDaoMysqlImpl implements UserDao { }
@Repository
public class UserDaoMongoImpl implements UserDao { }
// 注入时会报错
@Service
public class UserService {
@Autowired
private UserDao userDao;  // 错误:找到2个候选Bean
}

解决方案总结:

方案代码示例适用场景
@Qualifier@Qualifier("userDaoMysqlImpl")明确知道要用哪个Bean
@Primary在Bean上加@Primary有一个默认首选实现
字段名匹配private UserDao userDaoMysqlImpl简单场景
注入List/MapList<UserDao> userDaoList需要使用所有实现

4.6 可选依赖的处理

方式1:使用required=false

@Service
public class UserService {
@Autowired(required = false)  // 找不到Bean不报错,注入null
private CacheService cacheService;
public User getUser(Long id) {
if (cacheService != null) {
User cached = cacheService.get(id);
if (cached != null) return cached;
}
return userDao.findById(id);
}
}

方式2:使用Optional(更优雅)

@Service
public class UserService {
@Autowired
private Optional<CacheService> cacheService;
  public User getUser(Long id) {
  return cacheService
  .map(cache -> cache.get(id))
  .orElseGet(() -> userDao.findById(id));
  }
  }

4.7 自动装配的注意事项

注意1:理解装配时机

自动装配发生在Bean的属性注入阶段,在构造函数之后:

@Service
public class UserService {
@Autowired
private UserDao userDao;
public UserService() {
// 错误:此时userDao还未注入,为null
// userDao.findAll();
}
@PostConstruct
public void init() {
// 正确:此时userDao已经注入
userDao.findAll();
}
}

注意2:避免循环依赖

// 不推荐:循环依赖
@Service
public class UserService {
@Autowired
private OrderService orderService;
}
@Service
public class OrderService {
@Autowired
private UserService userService;
}
// 推荐:重新设计,单向依赖
@Service
public class OrderService {
@Autowired
private UserService userService;  // 单向依赖
}

4.8 自动装配与SpringBoot自动配置的区别

很多人容易混淆这两个概念:

自动装配(Auto-Wiring):

  • Spring的核心功能
  • 负责注入依赖
  • 通过@Autowired实现
  • Bean已存在,只是注入

自动配置(Auto-Configuration):

  • SpringBoot的特性
  • 负责创建Bean
  • 通过@EnableAutoConfiguration实现
  • 根据条件自动创建Bean

关系:

SpringBoot自动配置 → 创建Bean
         ↓
Spring自动装配 → 注入Bean

举例:

// SpringBoot自动配置:自动创建DataSource Bean
@Configuration
@ConditionalOnClass(DataSource.class)
public class DataSourceAutoConfiguration {
@Bean
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
}
// 自动装配:自动注入DataSource依赖
@Service
public class UserService {
@Autowired  // 自动装配
private DataSource dataSource;  // 这个Bean是自动配置创建的
}

五、其他注入注解对比

5.1 @Resource(JSR-250规范)

@Service
public class UserService {
@Resource  // 默认按名称装配
private UserDao userDao;
@Resource(name = "userDaoMysqlImpl")  // 指定Bean名称
private UserDao userDao2;
}

@Autowired vs @Resource:

特性@Autowired@Resource
来源Spring框架Java EE规范
默认装配方式按类型(byType)按名称(byName)
指定Bean配合@Qualifier使用name属性
支持required支持不支持
支持构造器注入支持不支持

建议: 优先使用@Autowired,功能更强大,是Spring原生注解。

5.2 @Inject(JSR-330)

来自Java依赖注入规范:

@Service
public class UserService {
@Inject  // 功能类似@Autowired
private UserDao userDao;
}

需要额外引入依赖:

<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>

@Inject vs @Autowired:

特性@Autowired@Inject
来源SpringJSR-330
是否支持required支持不支持
配合注解@Qualifier@Named

建议: 除非需要跨框架兼容,否则使用 @Autowired 即可。

5.3 @Value(注入配置值)

用于注入配置文件中的值,这是学习SpringBoot配置的基础:

@Service
public class UserService {
@Value("${app.name}")  // 从配置文件读取
private String appName;
@Value("${app.max-users:100}")  // 指定默认值100
private int maxUsers;
@Value("#{systemProperties['user.home']}")  // SpEL表达式
private String userHome;
}

配置文件(application.properties):

app.name=我的应用
app.max-users=500

六、常见问题与解决方案

问题1:循环依赖

什么是循环依赖?

两个或多个Bean相互依赖,形成闭环:

@Service
public class UserService {
@Autowired
private OrderService orderService;  // UserService依赖OrderService
}
@Service
public class OrderService {
@Autowired
private UserService userService;  // OrderService依赖UserService
}

Spring如何解决?

Spring通过三级缓存机制解决单例Bean的字段注入循环依赖:

  1. 一级缓存:存放完整的Bean实例
  2. 二级缓存:存放早期的Bean引用(已实例化但未完成依赖注入)
  3. 三级缓存:存放Bean工厂(用于创建代理对象)

无法解决的情况:构造器循环依赖

@Service
public class UserService {
private final OrderService orderService;
public UserService(OrderService orderService) {
this.orderService = orderService;
}
}
@Service
public class OrderService {
private final UserService userService;
public OrderService(UserService userService) {
this.userService = userService;  // 报错!无法解决
}
}

解决方法:

  1. 重新设计,消除循环依赖(最佳方案)
  2. 使用@Lazy延迟加载
@Service
public class UserService {
private final OrderService orderService;
public UserService(@Lazy OrderService orderService) {
this.orderService = orderService;  // 注入代理对象,延迟初始化
}
}
  1. 改用字段注入(不推荐,只是权宜之计)

问题2:注入的Bean为null

常见原因:

原因1:类没有被Spring管理

// 错误:忘记加@Service注解
public class UserService {
@Autowired
private UserDao userDao;  // 注入失败,为null
}
// 正确:添加@Service注解
@Service
public class UserService {
@Autowired
private UserDao userDao;  // 正常注入
}

原因2:包扫描路径不对

@SpringBootApplication
@ComponentScan("com.example.service")  // 只扫描service包
public class Application {
// UserDao在com.example.dao包下,扫描不到
}
// 正确:扫描父包
@SpringBootApplication
@ComponentScan("com.example")  // 扫描整个com.example包
public class Application { }

原因3:直接new对象,不从Spring容器获取

// 错误:直接new的对象,Spring无法注入依赖
UserService service = new UserService();
service.getUser(1L);  // userDao为null,报NPE
// 正确:从Spring容器获取
@RestController
public class UserController {
@Autowired
private UserService userService;  // 从容器获取,依赖已注入
@GetMapping("/user/{id}")
public User getUser(@PathVariable Long id) {
return userService.getUser(id);  // 正常使用
}
}

原因4:在静态字段上使用@Autowired

// 错误:无法注入静态字段
@Service
public class UserService {
@Autowired
private static UserDao userDao;  // 无法注入
}
// 正确:使用非静态字段
@Service
public class UserService {
@Autowired
private UserDao userDao;  // 正常注入
}

问题3:注入时机问题

错误示例:在构造函数中使用依赖

@Service
public class UserService {
@Autowired
private UserDao userDao;
private List<User> cache;
  // 错误:构造函数执行时,userDao还未注入
  public UserService() {
  this.cache = userDao.findAll();  // NPE!
  }
  }

正确做法:使用@PostConstruct

@Service
public class UserService {
@Autowired
private UserDao userDao;
private List<User> cache;
  @PostConstruct  // 在依赖注入完成后执行
  public void init() {
  this.cache = userDao.findAll();  // 正确
  }
  }

Bean的生命周期:

1. 实例化(执行构造函数)
   ↓
2. 依赖注入(@Autowired生效)
   ↓
3. 初始化前(@PostConstruct执行)
   ↓
4. 初始化(InitializingBean.afterPropertiesSet())
   ↓
5. Bean可用
   ↓
6. 销毁前(@PreDestroy执行)
   ↓
7. 销毁(DisposableBean.destroy())

七、最佳实践

1. 优先使用构造器注入

// 推荐
@Service
public class UserService {
private final UserDao userDao;  // final保证线程安全
public UserService(UserDao userDao) {
this.userDao = userDao;
}
}
//或者可以这样写,一个意思
@Service
@@RequiredArgsConstructor
public class UserService {
private final UserDao userDao;
}

2. 使用final保证不可变性

@Service
public class UserService {
private final UserDao userDao;  // final保证线程安全
public UserService(UserDao userDao) {
this.userDao = userDao;
}
}

3. 多个相同类型Bean时明确指定

@Service
public class UserService {
private final UserDao userDao;
public UserService(@Qualifier("userDaoMysqlImpl") UserDao userDao) {
this.userDao = userDao;
}
}

4. 可选依赖使用Optional

@Service
public class UserService {
@Autowired
private Optional<CacheService> cacheService;
  }

5. 避免循环依赖

重新设计类的职责,消除循环依赖。如果实在无法避免,使用@Lazy。

八、面试高频问题

问题1:@Autowired和@Resource的区别?

答案:

维度@Autowired@Resource
来源Spring框架Java EE规范(JSR-250)
装配方式默认byType,可配合@Qualifier按名称默认byName,可通过name属性指定
作用范围字段、构造器、方法、参数字段、方法
required属性支持不支持
推荐使用Spring项目推荐需要跨框架兼容时使用

问题2:什么是循环依赖?Spring如何解决?

答案:

循环依赖是指两个或多个Bean相互依赖,形成闭环。

Spring通过三级缓存解决单例Bean的循环依赖:

  1. 一级缓存:完整的Bean实例
  2. 二级缓存:早期的Bean引用(未完成依赖注入)
  3. 三级缓存:Bean工厂(用于创建代理对象)

注意:构造器循环依赖无法解决,需要使用@Lazy或重新设计。

问题3:为什么推荐使用构造器注入?

答案:

  1. 依赖明确:所有依赖在构造器中声明,一目了然
  2. 不可变性:可以使用final修饰,保证线程安全
  3. 便于测试:可以直接new对象传参,无需Spring容器
  4. 避免NPE:如果依赖为null,在创建时就会失败
  5. 强制完整性:必须提供所有依赖才能创建对象

问题4:@Autowired的装配流程是什么?

答案:

  1. Bean实例化(调用构造函数)
  2. AutowiredAnnotationBeanPostProcessor 扫描@Autowired注解
  3. 解析依赖类型
  4. 在容器中查找匹配的Bean:
    • 先按类型查找
    • 如果有多个,按@Primary筛选
    • 如果还有多个,按@Qualifier筛选
    • 如果还有多个,按字段名称匹配
  5. 通过反射注入依赖
  6. 调用@PostConstruct方法
  7. Bean初始化完成

问题5:如何解决多个相同类型Bean的注入问题?

答案:

  1. 使用 @Qualifier 指定Bean名称
  2. 使用 @Primary 标记主要Bean
  3. 使用字段名称匹配Bean名称
  4. 注入 List<T>Map<String, T> 获取所有Bean
  5. 使用 @Resource(name="beanName") 按名称注入

问题6:依赖注入和工厂模式有什么区别?

答案:

工厂模式:

  • 对象自己通过工厂获取依赖
  • 对象知道工厂的存在
  • 耦合度较高

依赖注入:

  • 容器主动将依赖注入到对象
  • 对象不知道容器的存在
  • 完全解耦

依赖注入是控制反转的一种实现方式,比工厂模式更彻底地解耦。

九、与SpringBoot的关系

理解了Spring的依赖注入,你就能更好地理解SpringBoot的自动配置原理。

SpringBoot如何简化依赖注入?

  1. 自动包扫描
@SpringBootApplication  // 包含@ComponentScan,自动扫描当前包及子包
//目标类标注 @Component 或其衍生注解,且类处于启动类所在包/子包下,SpringBoot 就会自动扫描并将其注册为 Bean 实例。
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
  1. 自动配置Bean

SpringBoot会自动配置常用的Bean(如DataSource、JdbcTemplate等),你只需注入使用:

@Service
public class UserService {
@Autowired
private JdbcTemplate jdbcTemplate;  // SpringBoot自动配置,直接注入
}
  1. Starter依赖

引入starter依赖,相关Bean自动配置:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
@Service
public class UserService {
@Autowired
private EntityManager entityManager;  // 自动配置,直接注入
}

本文是学习SpringBoot的基础:

  • SpringBoot的自动配置本质上就是自动创建Bean并注入依赖
  • 理解了依赖注入,才能理解@ConditionalOnBean等条件注解
  • 理解了依赖注入,才能理解Starter的工作原理

下一步学习: 阅读《SpringBoot自动配置原理深度解析》,理解SpringBoot如何自动创建和配置Bean。

十、推荐资源

官方文档

  • Spring Framework Reference:https://docs.spring.io/spring-framework/docs/current/reference/html/
  • Spring IoC Container:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans

源码阅读

  • Spring Framework:https://github.com/spring-projects/spring-framework
  • 重点类:
    • AutowiredAnnotationBeanPostProcessor
    • DefaultListableBeanFactory
    • AbstractAutowireCapableBeanFactory

十一、总结

核心要点:

  1. Bean是由Spring容器管理的对象
  2. 依赖是一个对象需要使用另一个对象
  3. 依赖注入是Spring把依赖对象注入给需要的对象
  4. 控制反转是把对象创建和管理的控制权交给Spring
  5. @Autowired默认按类型装配,可配合@Qualifier按名称
  6. 构造器注入是最佳实践,优于字段注入
  7. 循环依赖通过三级缓存解决,但构造器循环依赖无法解决

学习路线:

Spring依赖注入(本文)
    ↓
SpringBoot自动配置原理
    ↓
自定义Starter开发
    ↓
Spring AOP原理
    ↓
Spring事务管理

给读者的建议:

  1. 动手实践:写代码,打断点调试
  2. 阅读源码:看看AutowiredAnnotationBeanPostProcessor的实现
  3. 理解原理:知其然更要知其所以然
  4. 实际应用:在项目中使用最佳实践

如果这篇文章对你有帮助,请点赞、收藏、关注!有问题欢迎在评论区讨论。

作者:[识君啊]

不要做API的搬运工,要做原理的探索者!