成交型网站建设,有趣的网站代码,给网站做绝对路径,cms网站开发价格1.1 IoC#xff08;控制反转#xff09;和DI#xff08;依赖注入#xff09;在Spring框架中的核心作用
IoC#xff08;控制反转#xff09;#xff1a;
IoC是一种编程思想#xff0c;其目标是将对象的创建和依赖关系的维护从应用程序代码中分离出来#xff0c;交给一…1.1 IoC控制反转和DI依赖注入在Spring框架中的核心作用
IoC控制反转
IoC是一种编程思想其目标是将对象的创建和依赖关系的维护从应用程序代码中分离出来交给一个外部的容器如Spring IoC容器来管理。在IoC中控制权从应用程序代码即调用者转移到了外部容器。容器负责创建对象、管理对象的生命周期以及处理对象之间的依赖关系。通过IoC应用程序代码变得更加简洁和模块化因为它不再需要关心对象的创建和依赖关系的维护。
DI依赖注入
DI是IoC的一种具体实现方式也是Spring框架的核心特性之一。在DI中对象之间的依赖关系不是通过硬编码的方式如使用new关键字来建立的而是由容器在运行时动态地将依赖关系注入到对象中。DI有三种主要的实现方式构造器注入、setter方法注入和字段注入。通过DI我们可以更加灵活地管理对象之间的依赖关系因为我们可以在运行时动态地改变依赖关系而无需修改应用程序代码。
IoC和DI的关系
IoC和DI是密切相关的概念。IoC是一种编程思想而DI是实现IoC的一种具体技术。当我们说“使用IoC”时我们实际上是在说“使用DI来实现IoC”。在Spring框架中IoC容器通过DI来管理对象之间的依赖关系并实现了控制权的反转。
IoC和DI的好处
降低了代码之间的耦合度由于依赖关系是通过容器来管理的因此应用程序代码不再需要关心对象的创建和依赖关系的维护从而降低了代码之间的耦合度。提高了代码的可测试性由于依赖关系可以通过配置文件或注解来定义因此我们可以轻松地替换依赖对象来进行单元测试或集成测试。提高了代码的可维护性和可扩展性由于应用程序代码不再需要关心对象的创建和依赖关系的维护因此我们可以更加容易地修改或扩展代码。
Spring的依赖注入Dependency Injection, 简称DI 是Spring框架的核心功能之一它是一种实现对象间解耦、降低代码耦合度的技术。依赖注入的核心思想是将对象所依赖的外部资源如对象、值、配置等不由其内部创建或查找而是由外部容器如Spring容器在运行时动态地注入到对象中。 具体来说依赖注入有以下几个关键点
注入方式Spring提供了多种依赖注入的方式包括构造函数注入、setter方法注入和字段注入等。
构造函数注入通过调用类的构造函数并将所需依赖作为参数传递来实现。setter方法注入通过调用类的setter方法来设置依赖。字段注入直接在字段上使用注解如Autowired来注入依赖但这种方式通常不推荐因为它破坏了封装性。
注入时机依赖注入通常发生在Spring容器创建或更新Bean实例时。注入源Spring容器是依赖注入的源头它负责创建和管理Bean实例并在适当的时候将依赖注入到Bean中。
DI有两个主要的变体
构造函数注入
当使用构造函数注入时Spring IoC容器会尝试解析Bean的依赖关系并通过调用Bean的构造函数来创建其实例。如果在这个过程中遇到循环依赖即Bean A依赖于Bean B而Bean B又依赖于Bean A那么当Spring试图注入其中一个Bean的依赖时另一个Bean可能还没有完全创建好因为Spring还在调用它的构造函数。由于构造函数的特性它必须在对象创建时调用并且只能调用一次Spring IoC容器无法解决这种循环依赖因为此时它不能注入一个还没有完全创建好的Bean实例。因此Spring会抛出一个BeanCurrentlyInCreationException异常。
Setter注入
Setter注入允许在Bean的构造函数调用之后通过调用其setter方法来注入依赖项。这种注入方式使得Spring IoC容器能够处理循环依赖。当Spring遇到循环依赖时它会首先为每个Bean创建一个实例调用其无参构造函数或具有默认值的构造函数然后逐个设置这些Bean的依赖项通过调用setter方法。由于这些Bean实例在调用setter方法之前已经创建好了因此Spring可以安全地解决循环依赖问题。
基于构造器的依赖注入Constructor-based Dependency Injection是一种在对象创建时通过其构造函数来传递依赖项的技术。这种依赖注入方式有几个优点比如确保依赖项在对象被完全初始化之前就已经被设置以及确保依赖项在对象的整个生命周期内都是不可变的除非对象被重新创建。
在Spring框架中你可以使用基于构造器的依赖注入来配置你的beans。以下是一个简单的例子展示了如何在Spring的XML配置文件中使用基于构造器的依赖注入
bean idmyService classcom.example.MyService constructor-arg refmyDependency /
/bean bean idmyDependency classcom.example.MyDependency /在这个例子中MyService类有一个构造函数它接受一个MyDependency类型的参数。在Spring的配置文件中我们定义了一个id为myService的bean它的类为com.example.MyService。然后我们使用constructor-arg元素来指定构造函数参数的值这里我们使用ref属性来引用另一个id为myDependency的bean。
在Java类中对应的构造函数可能如下所示
package com.example; public class MyService { private final MyDependency myDependency; public MyService(MyDependency myDependency) { this.myDependency myDependency; } // ... 其他方法和属性 ...
}
class MyDependency { // ... 类的定义 ...
}在这个例子中MyService类有一个私有的final字段myDependency它只能在构造函数中被初始化。这确保了myDependency在MyService对象的整个生命周期内都是不可变的。
如果你更喜欢使用Java配置即使用Configuration和Bean注解的方式你也可以这样做
Configuration
public class AppConfig { Bean public MyDependency myDependency() { return new MyDependency(); } Bean public MyService myService(MyDependency myDependency) { return new MyService(myDependency); }
}在这个Java配置类中我们定义了两个Bean方法分别用于创建MyDependency和MyService的实例。myService方法接受一个MyDependency类型的参数这个参数是通过调用myDependency()方法获取的。这样Spring就会在创建MyService实例时自动调用myDependency()方法并将返回的MyDependency实例传递给MyService的构造函数。
基于Setter的依赖注入是一种在对象创建后通过调用其setter方法来设置依赖项的技术。这种方法允许对象在其生命周期的某个时刻获得其依赖项而不是在构造时就必须知道所有的依赖项。以下是使用基于Setter的依赖注入的示例
定义依赖类
首先我们定义一个依赖类UserDao它可能是一个数据访问对象DAO类用于与数据库交互。
public class UserDao { // 方法和属性...
}定义需要注入依赖的类
接下来我们定义一个需要UserDao实例的类UserService。该类包含一个私有的UserDao字段和一个公开的setter方法用于设置该字段。
public class UserService { private UserDao userDao; // Setter方法用于注入UserDao实例 public void setUserDao(UserDao userDao) { this.userDao userDao; } // 其他方法如使用userDao进行操作...
}在Spring配置文件中配置依赖注入
在Spring的XML配置文件中我们定义了两个bean一个用于UserDao另一个用于UserService。对于UserService bean我们使用property元素和ref属性来指定userDao属性的值该值是对userDao bean的引用。
beans xmlnshttp://www.springframework.org/schema/beans xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd bean iduserDao classcom.example.UserDao/ bean iduserService classcom.example.UserService property nameuserDao refuserDao/ /bean /beans当Spring容器启动时它会读取配置文件并创建定义的bean。对于userService beanSpring会首先创建一个UserService的实例然后调用其setUserDao方法并将userDao bean的实例作为参数传递。这样UserService就获得了它所需的UserDao依赖项。
字段注入是一种在Spring框架中常见的依赖注入方式其中使用注解如Autowired、Inject或Resource直接在类的字段上声明依赖。Spring容器会在创建bean的实例时自动查找匹配的bean来注入。尽管字段注入在某些情况下可能看起来更简洁但它确实可能破坏封装性因为依赖项是通过反射直接设置的而不是通过类的构造函数或setter方法。 下面是一个使用字段注入的示例
import org.springframework.beans.factory.annotation.Autowired; public class UserService { // 直接在字段上使用Autowired注解进行注入 Autowired private UserDao userDao; // 由于已经通过字段注入了依赖这里不需要提供setter方法 // 使用注入的userDao进行操作的方法 public void performAction() { // 使用userDao进行操作 userDao.doSomething(); }
} // 假设的UserDao类
public class UserDao { public void doSomething() { // 模拟数据库操作或其他业务逻辑 }
} // Spring配置如果使用Java配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; Configuration
public class AppConfig { Bean public UserDao userDao() { return new UserDao(); } Bean public UserService userService() { return new UserService(); }
}在上面的示例中UserService类有一个UserDao类型的字段userDao该字段上使用了Autowired注解。当Spring容器创建UserService的bean时它会查找一个类型为UserDao的bean来自动注入到userDao字段中。同样AppConfig类配置了UserDao和UserService的bean定义。
尽管字段注入在某些情况下很方便但它通常不是推荐的做法因为它违反了封装原则允许外部代码直接修改类的内部状态。此外字段注入可能会使测试更加困难因为依赖项是直接在字段上注入的而不是通过构造函数或setter方法这使得在测试中提供模拟依赖项变得更加复杂。因此在很多情况下构造函数注入或setter注入是更好的选择。