您的位置:首页 > 教育 > 培训 > 软件外包公司的优势和劣势_手机刷机网站大全_开网站需要什么流程_网络营销期末总结

软件外包公司的优势和劣势_手机刷机网站大全_开网站需要什么流程_网络营销期末总结

2025/4/3 2:47:02 来源:https://blog.csdn.net/nmsoftklb/article/details/145990827  浏览:    关键词:软件外包公司的优势和劣势_手机刷机网站大全_开网站需要什么流程_网络营销期末总结
软件外包公司的优势和劣势_手机刷机网站大全_开网站需要什么流程_网络营销期末总结

Spring 依赖注入(Dependency Injection,DI)是 Spring 框架的核心特性之一,它负责管理对象之间的依赖关系,降低了代码的耦合度,提高了代码的可测试性和可维护性。Spring 实现依赖注入的方式主要有以下几种,并结合底层原理进行说明:

1. 构造器注入(Constructor Injection):

  • 原理: Spring 通过调用 Bean 的构造方法来注入依赖。
  • 实现方式:
    • XML 配置: 使用 <constructor-arg> 标签。
    • 注解: 使用 @Autowired 注解(可以省略,Spring 4.3+ 支持在构造方法上隐式注入)。
    • JavaConfig:@Bean 方法中使用参数。
  • 优点:
    • 依赖关系在对象创建时就确定,保证了对象在使用时所有依赖都已就绪。
    • 依赖不可变(immutable),提高了对象的安全性。
    • 更容易发现依赖问题(编译时就能发现)。
  • 缺点:
    • 当依赖较多时,构造方法参数列表会很长,不够灵活。
    • 不适用于有多个可选依赖的情况。

示例:

public class MyService {private MyRepository myRepository;// 构造器注入@Autowired // 可省略public MyService(MyRepository myRepository) {this.myRepository = myRepository;}
}

2. Setter 方法注入(Setter Injection):

  • 原理: Spring 通过调用 Bean 的 setter 方法来注入依赖。
  • 实现方式:
    • XML 配置: 使用 <property> 标签。
    • 注解: 在 setter 方法上使用 @Autowired 注解。
    • JavaConfig:@Bean 方法中调用 setter 方法。
  • 优点:
    • 更灵活,可以在对象创建后修改依赖。
    • 适用于可选依赖。
  • 缺点:
    • 依赖关系在对象创建后才建立,可能导致在使用时依赖尚未注入(需要进行 null 检查)。
    • 依赖可变,可能导致对象状态不一致。

示例:

public class MyService {private MyRepository myRepository;// Setter 方法注入@Autowiredpublic void setMyRepository(MyRepository myRepository) {this.myRepository = myRepository;}
}

3. 字段注入(Field Injection):

  • 原理: Spring 通过反射直接设置 Bean 的字段值来注入依赖。
  • 实现方式:
    • 注解: 在字段上使用 @Autowired 注解。
  • 优点:
    • 最简洁,代码量最少。
  • 缺点:
    • 依赖关系不明确,可读性较差。
    • 破坏了封装性,可以直接修改私有字段。
    • 难以进行单元测试(需要使用反射来模拟依赖)。
    • 容易产生循环依赖

示例:

public class MyService {// 字段注入@Autowiredprivate MyRepository myRepository;
}

4. 方法注入(Method Injection,不常用):

  • 通过Lookup方法或者CGLIB代理,在每次调用方法时,获取新的实例。

底层原理(简化版):

  1. BeanDefinition 解析: Spring 容器启动时,会解析配置文件(XML、注解、JavaConfig),将 Bean 的定义信息(类名、依赖关系、作用域等)封装成 BeanDefinition 对象。
  2. Bean 实例化: 当需要获取 Bean 时,Spring 根据 BeanDefinition 中的信息,通过反射创建 Bean 的实例。
  3. 依赖注入:
    • 构造器注入: Spring 根据 BeanDefinition 中定义的构造方法参数,从容器中查找或创建相应的依赖对象,然后调用构造方法创建 Bean 实例。
    • Setter 方法注入: Spring 根据 BeanDefinition 中定义的属性和 setter 方法,从容器中查找或创建相应的依赖对象,然后调用 setter 方法注入依赖。
    • 字段注入: Spring 根据 BeanDefinition 中定义的字段和 @Autowired 注解,从容器中查找或创建相应的依赖对象,然后通过反射直接设置字段值。
  4. Bean 初始化: 依赖注入完成后,Spring 会调用 Bean 的初始化方法(如果有)。
  5. Bean 放入容器: 初始化完成后,Spring 将 Bean 放入容器中,供应用程序使用。

循环依赖问题:

  • 什么是循环依赖: 当两个或多个 Bean 相互依赖时,就会形成循环依赖。例如,A 依赖 B,B 依赖 A。
  • Spring 如何解决:
    • 构造器注入的循环依赖无法解决,会抛出异常。

    • Setter 方法注入和字段注入的循环依赖,Spring 可以通过“三级缓存”机制解决。

      • 一级缓存(singletonObjects): 存放完全初始化好的单例 Bean。
      • 二级缓存(earlySingletonObjects): 存放早期暴露的 Bean 实例(已创建但未完全初始化)。
      • 三级缓存(singletonFactories): 存放创建 Bean 实例的 ObjectFactory
    • 解决过程(简化版):

      1. 创建 A 实例,将 A 的 ObjectFactory 放入三级缓存,并暴露一个早期的 A 实例到二级缓存。
      2. A 注入 B,发现 B 不存在,开始创建 B 实例。
      3. 创建 B 实例,将 B 的 ObjectFactory 放入三级缓存,并暴露一个早期的 B 实例到二级缓存。
      4. B 注入 A,从二级缓存中获取早期的 A 实例(虽然 A 还未完全初始化,但 B 可以先持有 A 的引用)。
      5. B 完成初始化,放入一级缓存。
      6. A 继续初始化,注入 B(从一级缓存中获取),完成初始化,放入一级缓存。

总结:

Spring 通过多种方式实现依赖注入,包括构造器注入、Setter 方法注入和字段注入。底层原理是基于反射和 BeanDefinition 对象。Spring 通过“三级缓存”机制解决了 Setter 方法注入和字段注入的循环依赖问题。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com