多语言外贸网站源码,定制网站 报价,定做app需要多少钱,官方软件下载大全一、Spring 依赖注入概述 Spring 依赖注入#xff08;Dependency Injection#xff0c;DI#xff09;是一种重要的设计模式#xff0c;它在 Spring 框架中扮演着关键角色。依赖注入的核心概念是将对象所需的依赖关系由外部容器#xff08;通常是 Spring 容器#xff09;进…一、Spring 依赖注入概述 Spring 依赖注入Dependency InjectionDI是一种重要的设计模式它在 Spring 框架中扮演着关键角色。依赖注入的核心概念是将对象所需的依赖关系由外部容器通常是 Spring 容器进行管理和注入而不是让对象自己去创建和管理依赖。
这种方式具有极大的重要性。首先它实现了解耦。在传统的编程方式中对象之间的依赖关系通常是在对象内部通过直接实例化来建立的这会导致对象之间高度耦合难以维护和扩展。而依赖注入使得对象只关注自身的核心业务逻辑不需要关心依赖对象的创建和获取方式从而降低了对象之间的耦合度。
例如在一个企业级应用中一个业务服务类可能依赖于数据访问层的某个 DAOData Access Object。如果采用传统方式业务服务类需要自己实例化 DAO 对象这样一旦 DAO 的实现发生变化业务服务类也需要相应修改。但通过依赖注入业务服务类只需要声明对 DAO 的依赖由 Spring 容器在运行时将合适的 DAO 实例注入到业务服务类中大大提高了代码的可维护性。
此外依赖注入还提高了代码的可测试性。在单元测试中可以轻松地替换依赖对象模拟不同的场景而不需要实际创建复杂的依赖关系。
总之Spring 依赖注入通过将对象的依赖关系外部化实现了解耦和可维护性是 Spring 框架中不可或缺的一部分。
二、常见的依赖注入方式 一属性注入
属性注入是一种常见的依赖注入方式它通过 set 方法注入 Bean 的属性值或依赖对象。这种方式具有很高的灵活性因为可以在对象实例化后根据需要动态地设置属性值。
例如在一个 Java 项目中有一个名为UserService的服务类它依赖于一个UserRepository接口的实现类来进行用户数据的操作。如果使用属性注入可以在UserService类中定义一个UserRepository类型的属性并提供对应的 set 方法。在 Spring 配置文件中可以通过property标签将具体的UserRepository实现类注入到UserService中。
属性注入的优点在于灵活性高可以根据不同的情况在运行时动态地设置属性值。同时对于一些可选的依赖关系也可以在需要的时候进行注入而不是在对象实例化时强制注入。
二构造函数注入
构造函数注入是在对象实例化时通过构造函数设置必要的属性。这种方式确保了对象实例化后即可使用因为所有必要的依赖都在对象创建时被注入。
以一个学生管理系统为例有一个Student类它有name、age和grade等属性。如果使用构造函数注入可以在Student类的构造函数中接收这些属性的值并在对象创建时进行初始化。在 Spring 配置文件中可以使用constructor-arg标签来指定构造函数的参数值。
构造函数注入的优点在于可以确保对象在创建时就处于一个完整的状态避免了在使用对象之前可能出现的未初始化状态。同时它也使得对象的依赖关系更加明确因为在构造函数中可以清楚地看到对象所依赖的所有资源。
三Setter 方法注入
Setter 方法注入是在对象实例化后通过调用 setter 方法实现依赖注入。这种方式使得依赖关系成为可选的因为可以在需要的时候才进行注入。
比如在一个电商系统中有一个Order类它依赖于一个PaymentService类来处理支付操作。如果使用 Setter 方法注入可以在Order类中定义一个PaymentService类型的属性并提供对应的 setter 方法。在需要进行支付操作时可以通过 Spring 容器调用 setter 方法将PaymentService实例注入到Order对象中。
Setter 方法注入的优点在于灵活性高可以根据不同的业务场景在运行时动态地注入依赖关系。同时对于一些可选的依赖也可以在需要的时候进行注入而不会在对象实例化时强制注入不必要的依赖。
三、其他依赖注入方式 一基于注解的自动装配
Autowired注解是 Spring 框架中用于自动装配的重要注解之一。它可以应用于构造器、字段和方法注入。
在构造器注入中当Autowired注解用于构造器时Spring 会在创建 Bean 实例时自动调用该构造器并为其参数注入对应类型的实例。例如
Servicepublic class DriverServiceImpl implements DriverService {private DriverDao driverDao;Autowiredpublic DriverServiceImpl(DriverDao driverDao) {this.driverDao driverDao;}}
在接口注入中Autowired可以用于接口的实现类自动注入实现接口的具体对象。
在方法注入中如果方法有参数会使用Autowired的方式在容器中查找是否有该参数并执行该方法。比如 Autowiredpublic void commonMethod(Bean04 bean04){System.out.println(普通方法的执行);}
Autowired默认按类型注入。这意味着 Spring 容器会自动查找与所需类型匹配的 Bean 进行注入。此时要求 Spring 容器中有且仅有一个合适的 Bean 为其赋值。但如果项目中有多个 Bean 可以赋值则会发生错误。可以通过结合Qualifier注解来指定具体的 Bean 名称进行注入避免这种错误。
二Resource 注入
Resource注解是 Java 标准JSR-250提供的注解Spring 也支持该注解。它主要有name和type两个重要属性。
如果同时指定了name和type则从 Spring 上下文中找到唯一匹配的 bean 进行装配找不到则抛出异常。例如 Resource(name myBean, type MyBean.class)private MyBean myBean;
如果指定了name则从上下文中查找名称id匹配的 bean 进行装配找不到则抛出异常。
如果指定了type则从上下文中找到类型匹配的唯一 bean 进行装配找不到或者找到多个都会抛出异常。
如果既没有指定name又没有指定type则自动按照 byName 方式进行装配如果没有匹配则回退为一个原始类型进行匹配如果匹配则自动装配。
三接口注入
接口注入是一种通过接口来实现依赖注入的方式。在接口中定义要注入的信息然后通过实现该接口的类来完成注入。
例如 public class ClassA {private InterfaceB clzB;public init() {Object obj Class.forName(Config.BImplementation).newInstance();clzB (InterfaceB)obj;}}
在这种方式中通过接口将调用者与实现者分离提高了代码的可维护性和可扩展性。但接口注入模式因为具备侵入性它要求组件必须与特定的接口相关联因此并不被看好实际使用有限。
四、不同注入方式对比 一可靠性
属性注入不可靠。属性注入是在对象实例化后通过 set 方法进行注入这意味着在对象使用过程中属性可能会被意外修改导致对象状态不可预测。
构造函数注入可靠。构造函数注入在对象实例化时就将所有必要的依赖注入一旦对象创建完成其依赖关系就不会再发生变化保证了对象的稳定性和可靠性。
Setter 方法注入不可靠。虽然 Setter 方法注入可以在对象实例化后进行依赖注入但这也使得对象的依赖关系可以在运行时被随意修改增加了对象状态的不确定性。
二可维护性
属性注入差。属性注入的依赖关系不明显难以直接从代码中看出对象的依赖关系不利于代码的维护和理解。
构造函数注入好。构造函数中明确列出了对象所依赖的资源使得依赖关系一目了然方便开发者进行代码维护和分析。
Setter 方法注入差。Setter 方法注入的依赖关系也不够直观需要通过查看 setter 方法才能确定对象的依赖关系增加了维护的难度。
三可测试性
属性注入差。在进行单元测试时由于属性注入的对象可能会受到外部环境的影响难以进行有效的模拟和控制导致测试难度较大。
构造函数注入好。构造函数注入使得对象的依赖关系在创建时就确定在单元测试中可以方便地通过构造函数传入模拟的依赖对象进行测试。
Setter 方法注入好。Setter 方法注入可以在测试时根据需要设置不同的依赖对象方便进行各种场景的测试。
四灵活性
属性注入很灵活。属性注入可以在对象实例化后根据需要动态地设置属性值对于一些可选的依赖关系非常方便。但这种灵活性也可能导致代码的混乱和不可控。
构造函数注入不灵活。构造函数注入在对象创建时就确定了依赖关系不能在运行时进行修改缺乏一定的灵活性。
Setter 方法注入很灵活。Setter 方法注入可以在对象实例化后根据业务需求动态地注入依赖关系具有较高的灵活性。但也可能导致依赖关系的不明确和代码的复杂性。
五循环关系检测
属性注入不检测。属性注入方式不会自动检测 Bean 之间的循环依赖关系可能会导致应用程序出现问题而难以排查。
构造函数注入自动检测。构造函数注入在对象创建时会自动检测循环依赖关系如果存在循环依赖会抛出异常便于开发者及时发现和解决问题。
Setter 方法注入不检测。Setter 方法注入也不会自动检测循环依赖关系可能会导致应用程序出现死锁等问题。
六性能表现
属性注入启动快。属性注入在启动时不需要进行复杂的依赖关系处理启动速度相对较快。
构造函数注入启动慢。构造函数注入需要在对象创建时处理所有的依赖关系这可能会导致启动时间延长。
Setter 方法注入启动快。Setter 方法注入在对象实例化时不需要处理依赖关系可以在需要时进行注入启动速度相对较快。
五、Spring 官方推荐及原因 Spring 官方推荐构造器注入这一推荐有多个重要原因。
首先IDEA 警告提示 “Field injection is not recommended”即不建议使用属性注入字段注入。这是因为属性注入存在一些弊端。属性注入是通过在类的变量上使用注解进行依赖注入本质上是通过反射的方式直接注入到字段。虽然这种方式非常简洁代码看起来简单易懂类可以专注于业务而不被依赖注入所污染只需要把注解扔到变量之上就好不需要特殊的构造器或者 set 方法依赖注入容器会提供所需的依赖。但是成也萧何败也萧何属性注入也会引发很多问题。
一方面容易违背单一职责原则。使用属性注入方式添加依赖很简单普通开发者很可能会无意识地给一个类添加很多依赖而当使用构造器方式注入到了某个特定的点构造器中的参数变得太多以至于很明显地发现 something is wrong。拥有太多的依赖通常意味着类要承担更多的责任明显违背了单一职责原则。
另一方面属性注入会导致依赖注入与容器本身耦合。具体表现为类和依赖容器强耦合不能在容器外使用不能绕过反射例如单元测试的时候进行实例化必须通过依赖容器才能实例化这更像是集成测试不能使用属性注入的方式构建不可变对象final 修饰的变量。
其次Spring 开发团队建议 “Always use constructor based dependency injection in your beans. Always use assertions for mandatory dependencies”即在 beans 中永远使用基于构造器的依赖注入对于必须的依赖永远使用断言来确认。构造器注入有以下几个好处
易于测试构造器注入使得对类的单元测试变得更加容易。通过将依赖项作为构造函数的参数传递可以轻松地在测试中传递模拟对象或存根对象从而控制和验证类的行为。例如对于一个OrderService类其依赖于OrderRepository在单元测试中可以轻松传入模拟的OrderRepository对象以验证OrderService的行为。
易于理解和维护构造器注入提供了清晰的依赖关系使代码更易于理解和维护。构造函数参数直观地表示了类所需的依赖项降低了代码的复杂性。比如PaymentProcessor依赖于PaymentGateway通过构造器注入一目了然。
依赖注入的一致性构造器注入鼓励将所有依赖项都放在构造函数中从而确保类的实例在被创建时处于一致的状态。这有助于避免在使用对象时遇到空指针异常或未初始化的依赖项。
不可变性通过使用final关键字构造器注入可以实现不可变性这意味着一旦依赖项被设置它们不能再被修改。这可以提高代码的安全性和稳定性。例如ShoppingCart类通过构造器注入一个不可变的ListItem。
依赖项解析构造器注入使依赖项的解析变得更加明确。当容器创建 Bean 实例时容器只需查找所需的构造函数参数而不需要进行复杂的解析或猜测。
避免循环依赖构造器注入有助于避免循环依赖问题因为在创建 Bean 实例时构造函数参数必须已经可用。这有助于减少潜在的运行时错误。
综上所述Spring 官方推荐构造器注入是出于提高代码质量、可测试性和可维护性的考虑。