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注入
@Autowired
+@Service
)
指定总结
两种方式最终目的相同:都是让 Spring 容器管理对象并注入依赖。
- XML 是「外部配置」,更适合需要频繁修改依赖关系或管理第三方类的场景;
- 注解是「内部标注」,更简洁且开发效率高,是现在的主流方式。
在 Spring 自动注入时,类是否需要无参构造函数,取决于注入方式和类的构造情况,并非绝对必须。具体可以分为以下几种情况:
- 使用
@Autowired
注入字段或 setter 方法时:** 不需要无参构造函数如果类中的依赖是通过「字段注入」或「setter 方法注入」的,那么 Spring 实例化这个类时,默认会调用无参构造函数 **,但如果类中显式定义了其他构造函数(例如有参构造),而没有显式定义无参构造函数,就会报错。
示例(正确情况):
@Servicepublic class UserService { // 字段注入 @Autowired private UserDao userDao; // 类中没有显式定义任何构造函数 → 编译器会自动生成默认无参构造函数 // Spring 可以正常实例化}
示例(错误情况):
@Servicepublic class UserService { @Autowired private UserDao userDao; // 显式定义了有参构造函数,且没有定义无参构造函数 public UserService(String name) { // ... }}
此时 Spring 会报错,因为类中没有无参构造函数,无法通过默认方式实例化对象。
- 使用构造函数注入时:** 可以不需要无参构造函数**如果类通过「构造函数注入」依赖(即构造函数上添加
@Autowired
),那么:
- 只要 Spring 能通过该构造函数传入所需的参数,就可以实例化对象
- 此时即使没有无参构造函数,也完全没问题
示例(正确情况):
@Servicepublic class UserService { private UserDao userDao; // 构造函数注入(@Autowired 可以省略,Spring 5.0+ 对单构造函数默认自动注入) public UserService(UserDao userDao) { this.userDao = userDao; } // 没有无参构造函数,但 Spring 可以通过有参构造函数实例化}
- 核心结论
- 无参构造函数的必要性,取决于类是否显式定义了其他构造函数:
- 如果类中没有显式定义任何构造函数:编译器会自动生成默认无参构造函数,Spring 可以正常实例化(无论注入方式如何)。
- 如果类中显式定义了有参构造函数:
- 若使用「字段注入」或「setter 注入」:必须手动添加无参构造函数,否则 Spring 无法实例化。
- 若使用「构造函数注入」:无需无参构造函数,Spring 会通过有参构造函数注入依赖并实例化。
最佳实践
- 推荐使用构造函数注入(更符合依赖注入的设计原则,且避免无参构造函数问题)。
- 若使用字段注入,且类中需要定义有参构造函数,务必手动添加无参构造函数,例如:
@Servicepublic class UserService { @Autowired private UserDao userDao; // 有参构造函数 public UserService(String name) { // ... } // 手动添加无参构造函数 public UserService() { }}