> 技术文档 > Spring 相关知识点

Spring 相关知识点


文章目录

      • 一、IOC
      • 二、bean
      • 三、注解注入和xml注入

一、IOC

IOC 即控制反转(Inversion of Control),是一种设计原则,旨在减少计算机程序中代码之间的耦合性。

  • IOC容器:是实现IOC原则的核心组件,负责管理对象的创建、配置和生命周期。常见的IOC容器有Spring框架提供的容器、Google Guice、Java EE CDI等。其主要职责包括对象创建、依赖注入和生命周期管理。
  • 依赖注入(DI):是实现IOC的一种方式,通过将对象的依赖关系注入到对象中,达到控制反转的目的。主要有三种方式:
    • 构造函数注入:通过构造方法将依赖对象传递给需要依赖的对象。
    • setter方法注入:通过setter方法将依赖对象注入到需要依赖的对象中。
    • 接口注入:通过接口将依赖对象注入到需要依赖的对象中。
  • 优势
    • 松耦合:对象间依赖关系由容器管理,降低了代码耦合度。
    • 可测试性:依赖关系通过容器注入,便于在测试中替换为mock对象,独立测试每个模块。
    • 可维护性和扩展性:可通过配置文件或注解轻松替换实现或修改依赖关系,无需大量修改代码。
    • 符合“面向接口编程”原则:鼓励通过接口定义依赖,提升系统灵活性,便于替换和扩展。
  • 实现策略
    • 依赖查找:容器提供回调接口和上下文条件给组件,组件使用容器提供的API来查找资源和协作对象。
    • 依赖注入:组件不做定位查询,只提供普通Java方法让容器去决定依赖关系,容器把符合依赖关系的对象通过JavaBean属性或者构造函数传递给需要的对象。
  • 在Spring中的应用:Spring是Java领域常用的IOC容器,提供XML配置、注解配置和Java配置类等多种配置方式。可通过ApplicationContext来管理和获取Spring容器中的Bean。常用注解有@Component、@Repository、@Service、@Controller、@Autowired等。
    • ApplicationContext是Spring框架中核心的接口之一,代表Spring的IOC容器,负责管理应用中的BEAN组件的生命周期,包括创建等。
    • 它的实现类有ClassPathXmlApplicationContext,这用来读配置文件

二、bean

在 Spring 等 Java 框架的配置文件中,Bean 是指由框架容器创建、管理和销毁的对象。它是框架实现控制反转(IoC)和依赖注入(DI)的核心概念。

简单来说,Bean 就是:

  • 由框架容器(而非开发者手动 new)创建的对象
  • 其生命周期(创建、初始化、销毁)由容器管理
  • 可以通过配置文件(如 XML)或注解(如 @Component)定义
  • 可以在配置中指定依赖关系,由容器自动注入

例如在 Spring 的 XML 配置文件中,一个 Bean 的定义可能像这样:

<bean id=\"userService\" class=\"com.example.UserService\">  <property name=\"userDao\" ref=\"userDao\"/></bean>

这里定义了一个 ID 为 userService 的 Bean,对应 UserService 类,框架会自动创建该对象并注入其依赖的 userDao Bean。

通过这种方式,开发者无需手动管理对象的创建和依赖关系,而是交由框架统一管理,从而实现了代码的解耦和灵活性。

三、注解注入和xml注入

维度 XML 配置注入 注解注入(如 @Autowired+@Service配置位置 独立的 XML 文件中 直接写在 Java 类的代码中 依赖关系声明 显式通过 指定 隐式通过注解自动匹配(默认按类型) 修改依赖 改 XML 文件,无需重新编译代码 改注解或代码,可能需要重新编译 可读性 集中管理所有 Bean 关系,适合复杂系统 依赖关系分散在类中,直观但分散 灵活性 不侵入代码,适合第三方类注入 侵入代码,但开发效率更高

总结

两种方式最终目的相同:都是让 Spring 容器管理对象并注入依赖。

  • XML 是「外部配置」,更适合需要频繁修改依赖关系或管理第三方类的场景;
  • 注解是「内部标注」,更简洁且开发效率高,是现在的主流方式。

在 Spring 自动注入时,类是否需要无参构造函数,取决于注入方式和类的构造情况,并非绝对必须。具体可以分为以下几种情况:

  1. 使用 @Autowired 注入字段或 setter 方法时:** 不需要无参构造函数如果类中的依赖是通过「字段注入」或「setter 方法注入」的,那么 Spring 实例化这个类时,默认会调用无参构造函数 **,但如果类中显式定义了其他构造函数(例如有参构造),而没有显式定义无参构造函数,就会报错。

示例(正确情况):

@Servicepublic class UserService { // 字段注入 @Autowired private UserDao userDao; // 类中没有显式定义任何构造函数 → 编译器会自动生成默认无参构造函数 // Spring 可以正常实例化}

示例(错误情况):

@Servicepublic class UserService { @Autowired private UserDao userDao; // 显式定义了有参构造函数,且没有定义无参构造函数 public UserService(String name) { // ... }}

此时 Spring 会报错,因为类中没有无参构造函数,无法通过默认方式实例化对象。

  1. 使用构造函数注入时:** 可以不需要无参构造函数**如果类通过「构造函数注入」依赖(即构造函数上添加 @Autowired),那么:
  • 只要 Spring 能通过该构造函数传入所需的参数,就可以实例化对象
  • 此时即使没有无参构造函数,也完全没问题

示例(正确情况):

@Servicepublic class UserService { private UserDao userDao; // 构造函数注入(@Autowired 可以省略,Spring 5.0+ 对单构造函数默认自动注入) public UserService(UserDao userDao) { this.userDao = userDao; } // 没有无参构造函数,但 Spring 可以通过有参构造函数实例化}
  1. 核心结论
  • 无参构造函数的必要性,取决于类是否显式定义了其他构造函数
    • 如果类中没有显式定义任何构造函数:编译器会自动生成默认无参构造函数,Spring 可以正常实例化(无论注入方式如何)。
    • 如果类中显式定义了有参构造函数
      • 若使用「字段注入」或「setter 注入」:必须手动添加无参构造函数,否则 Spring 无法实例化。
      • 若使用「构造函数注入」:无需无参构造函数,Spring 会通过有参构造函数注入依赖并实例化。

最佳实践

  • 推荐使用构造函数注入(更符合依赖注入的设计原则,且避免无参构造函数问题)。
  • 若使用字段注入,且类中需要定义有参构造函数,务必手动添加无参构造函数,例如:
    @Servicepublic class UserService { @Autowired private UserDao userDao; // 有参构造函数 public UserService(String name) { // ... } // 手动添加无参构造函数 public UserService() { }}