0

黑马程序员新版Spring零基础入门到精通

jiuo
6天前 8

获课:789it.top/14165/


一、依赖注入(DI)的核心原理

依赖注入是Spring框架的核心设计模式,通过控制反转(IoC)容器实现对象间依赖关系的解耦。其底层机制可分为三个阶段:

  1. 元数据收集阶段
    Spring容器启动时,通过组件扫描(@ComponentScan)识别带有@Component@Service等注解的类,将其注册为Bean定义并存储在BeanDefinitionMap中。对于显式依赖(如构造函数参数、字段类型),容器会记录其类型信息。

  2. 依赖解析阶段
    当Bean实例化时,容器根据依赖类型(Type)在上下文中查找匹配的Bean。若存在多个同类型Bean,则进一步通过字段名或@Qualifier注解指定的名称进行筛选。例如:

    java@Servicepublic class UserService {    @Autowired    @Qualifier("mysqlUserRepository") // 明确指定Bean名称    private UserRepository userRepository;}
  3. 依赖注入阶段
    通过反射机制将解析到的依赖对象注入目标Bean的字段、方法或构造函数中。此过程由AutowiredAnnotationBeanPostProcessor处理,其postProcessProperties方法会扫描@Autowired注解并完成注入。

二、自动装配的三种实现方式

Spring支持XML、注解和Java配置三种自动装配方式,现代开发中注解方式已成为主流:

  1. XML配置(遗留系统)
    通过<bean>标签的autowire属性指定装配模式:
    • byName:按属性名匹配Bean名称。
    • byType:按属性类型匹配Bean类型。
    • constructor:通过构造函数参数类型匹配。
  2. 注解配置(推荐)
    • @Autowired:默认按类型装配,支持required=false实现可选依赖。
    • @Resource(JSR-250):默认按名称装配,未指定名称时回退到按类型。
    • @Inject(JSR-330):功能与@Autowired类似,需Spring 6.x内置支持。
  3. Java配置
    通过@Configuration@Bean注解以编程方式定义Bean及其依赖,提供类型安全性和灵活性:
    java@Configurationpublic class AppConfig {    @Bean    public UserDao userDao() { return new UserDao(); }        @Bean    public UserService userService(UserDao userDao) {         return new UserService(userDao); // 参数直接注入    }}

三、@Autowired的底层实现机制

@Autowired的实现依赖于Spring的BeanPostProcessor体系,其核心流程如下:

  1. 后置处理器注册
    Spring容器启动时,注册AutowiredAnnotationBeanPostProcessor,该处理器专门处理@Autowired@Value注解。

  2. 依赖注入触发时机
    在Bean初始化阶段(populateBean方法),容器调用AutowiredAnnotationBeanPostProcessorpostProcessProperties方法,扫描目标Bean的字段、方法或构造函数上的@Autowired注解。

  3. 依赖解析与注入

    • 字段注入:直接通过反射设置字段值,需注意破坏封装性。
    • 方法注入:调用Setter方法或任意方法完成注入,适合延迟初始化场景。
    • 构造器注入:推荐方式,保证依赖不可变且避免循环依赖问题。Spring通过SmartInstantiationAwareBeanPostProcessordetermineCandidateConstructors方法确定最佳构造器。
  4. 循环依赖处理
    Spring通过三级缓存机制解决循环依赖:

    • 一级缓存:存储完全初始化好的Bean。
    • 二级缓存:存储早期暴露的Bean(尚未完成属性填充和初始化)。
    • 三级缓存:存储Bean的创建工厂(ObjectFactory),用于获取代理对象。

四、最佳实践与避坑指南

  1. 构造器注入优先
    构造器注入可确保依赖不可变,且Spring能直接检测循环依赖(此时会抛出BeanCurrentlyInCreationException)。示例:

    java@Servicepublic class OrderService {    private final PaymentService paymentService;        @Autowired // 可省略,Spring 4.3+支持单构造器自动注入    public OrderService(PaymentService paymentService) {        this.paymentService = paymentService;    }}
  2. 避免字段注入
    字段注入破坏封装性,且不利于单元测试(需通过反射注入依赖)。若必须使用,可结合Lombok的@RequiredArgsConstructor实现构造器注入的简洁写法。

  3. 明确指定@Qualifier
    当存在多个同类型Bean时,务必通过@Qualifier消除歧义,避免Spring抛出NoUniqueBeanDefinitionException

  4. 处理可选依赖
    通过@Autowired(required = false)声明可选依赖,或使用Optional类型(Spring 6.x支持更优雅的结合):

    java@Autowired(required = false)private Optional<NotificationService> notificationService;
  5. 警惕循环依赖
    循环依赖通常表明设计问题,应通过重构代码(如引入中间层、拆分Bean)解决。若必须保留,可使用Setter注入或@Lazy延迟加载,但需谨慎评估影响。


本站不存储任何实质资源,该帖为网盘用户发布的网盘链接介绍帖,本文内所有链接指向的云盘网盘资源,其版权归版权方所有!其实际管理权为帖子发布者所有,本站无法操作相关资源。如您认为本站任何介绍帖侵犯了您的合法版权,请发送邮件 [email protected] 进行投诉,我们将在确认本文链接指向的资源存在侵权后,立即删除相关介绍帖子!
最新回复 (0)

    暂无评论

请先登录后发表评论!

返回
请先登录后发表评论!