📜  Spring 依赖注入与示例

📅  最后修改于: 2022-05-13 01:55:10.620000             🧑  作者: Mango

Spring 依赖注入与示例

什么是依赖注入:
依赖注入是Spring IOC(Inversion of Control)提供的主要功能。 Spring-Core 模块负责通过 Constructor 或 Setter 方法注入依赖项。控制反转的设计原则强调保持Java类相互独立,容器将它们从对象创建和维护中解放出来。这些由 Spring 管理的类必须遵守 Java-Bean 的标准定义。 Spring 中的依赖注入还确保了类之间的松散耦合。
依赖注入的需要:
假设类一需要类二的对象来实例化或操作一个方法,则称类一依赖于类二。现在虽然依赖一个模块看起来不错,但在现实世界中,这可能会导致很多问题,包括系统故障。因此,需要避免这种依赖关系。
Spring IOC 使用 Dependency Injection 解决了此类依赖关系,这使得代码更易于测试和重用。通过为通用功能定义接口可以实现类之间的松散耦合,并且注入器将实例化所需实现的对象。实例化对象的任务由容器根据开发者指定的配置完成。
Spring依赖注入的类型:
Spring 依赖注入有两种类型。他们是:

  1. Setter Dependency Injection (SDI) :这是两种 DI 方法中较简单的一种。在此,DI 将在 setter 和/或 getter 方法的帮助下注入。现在要将 DI 设置为 bean 中的 SDI,这是通过bean-configuration 文件完成的。为此,要使用 SDI 设置的属性在 bean-config 文件中的标记下声明。
    示例:假设有一个使用 SDI 并设置属性 geeks 的 GFG 类。它的代码如下所示。
Java
package com.geeksforgeeks.org;
 
import com.geeksforgeeks.org.IGeek;
 
public class GFG {
 
    // The object of the interface IGeek
    IGeek geek;
 
    // Setter method for property geek
    public void setGeek(IGeek geek)
    {
        this.geek = geek;
    }
}


XML

 
    
        
            
        
    
     


         


Java
package com.geeksforgeeks.org;
 
import com.geeksforgeeks.org.IGeek;
 
public class GFG {
 
    // The object of the interface IGeek
    IGeek geek;
 
    // Constructor to set the CDI
    GFG(IGeek geek)
    {
        this.geek = geek;
    }
}


XML

 
    
        
            
        
    
     


         


  1. 在 bean-config 文件中设置 SDI:

XML


 
    
        
            
        
    
     


         

  1. 这在 setter 方法 ('setGeek') 的帮助下将'CsvGFG' bean 注入到'GFG' 对象中
  2. 构造函数依赖注入(CDI) :在这种情况下,DI将在构造函数的帮助下被注入。现在要将 DI 设置为 bean 中的 CDI,这是通过bean-configuration 文件完成的。为此,要使用 CDI 设置的属性在 bean-config 文件中的标记下声明。
    示例:让我们以与 SDI 相同的示例为例

Java

package com.geeksforgeeks.org;
 
import com.geeksforgeeks.org.IGeek;
 
public class GFG {
 
    // The object of the interface IGeek
    IGeek geek;
 
    // Constructor to set the CDI
    GFG(IGeek geek)
    {
        this.geek = geek;
    }
}
  1. 在 bean-config 文件中设置 CDI:

XML


 
    
        
            
        
    
     


         

  1. 这在构造函数的帮助下将“CsvGFG”bean 注入到“GFG”对象中。

Setter 依赖注入 (SDI) 与构造函数依赖注入 (CDI)

Setter DIConstructor DI
Poor readability as it adds a lot of boiler plate codes in the application.Good readability as it is separately present in the code.
The bean must include getter and setter methods for the properties.The bean class must declare a matching constructor with arguments. Otherwise, BeanCreationException will be thrown.
Requires addition of @Autowired annotation, above the setter in the code and hence, it increases the coupling between the class and the DI container.Best in the case of loose coupling with the DI container as it is not even required to add @Autowired annotation in the code.(Implicit constructor injections for single constructor scenarios after spring 4.0)
Circular dependencies or partial dependencies result with Setter DI because object creation happens before the injections.No scope for circular or partial dependency because dependencies are resolved before object creation itself.
Preferred option when properties are less and mutable objects can be created.Preferred option when properties on the bean are more and immutable objects (eg: financial processes) are important for application.

Spring DI 示例:

  • 我们使用三个类和一个接口作为 bean 来举例说明 CDI 和 SDI 的概念。它们分别是 Vehicle、ToyotaEngine、Tires 类和 IEngine 接口。
  • 从我们的示例中,我们可以看到 Vehicle 类依赖于 Engine 的实现,它是一个接口。 (因此,基本上,车辆制造商想要一个符合印度排放标准的标准发动机。) ToyotaEngine 类实现接口,它的引用在映射到 Vehicle 类属性之一的 bean 配置文件中提供。
  • 在 Vehicle 类中,我们调用应用程序上下文并执行 bean 实例化。 Vehicle 类的两个对象被实例化。 'obj1' 通过名为InjectwithConstructor的 bean 实例化。 bean 名称可以位于 bean 配置文件中。类似地,'obj2' 是通过名称为InjectwithSetter的 bean 实例化的。
  • 可以观察到'obj1'是通过构造函数注入的,'obj2'使用setter注入。
  • 在下面的 bean 配置文件中,我们使用了两个 Vehicle bean 的声明。
  • InjectwithConstructor bean 使用元素 constructor-arg,带有属性 name 和 ref。 “名称”属性与 Vehicle 类定义中给出的构造函数参数名称相关。 'ref' 属性指向可用于注入的 bean 引用。
  • InjectwithSetter利用属性元素来提供属性的“名称”和属性的“值”。代替值属性 'ref' 可用于表示对 bean 的引用。
  • 在配置细节中,我们将 ToyotaBean 引用注入到 Vehicle 类 constructor-arg 中的 IEngine 引用中,其中 IEngine 是一个接口,需要一个实现类引用来进行 bean 注入。
  • 我们为 Tires 类使用了两个单独的 bean 引用,分别通过 setter 和构造函数注入。我们可以观察到 'tyre1Bean' 和 'tyre2Bean' 是用每个属性的字符串字面量初始化的。

pom.xml


  
    
    
        org.springframework
        spring-core
        4.3.11.RELEASE
    
  
    
    
        org.springframework
        spring-context
        4.3.11.RELEASE
    

恩尼涅。Java
interface IEngine {
    String EMISSION_NORMS = "BSIV";
    String importOrigin();
    double cost();
}

丰田发动机。Java
public class ToyotaEngine implements IEngine {
    String company;
    double cost;
    public double getCost()
    {
        return cost;
    }

    public void setCost(double cost)
    {
        cost = this.cost;
    }

    public String getCompany()
    {
        return company;
    }

    public void setCompany(String company)
    {
        this.company = company;
    }

    @Override
    public String importOrigin()
    {
        return "Japan";
    }

    @Override
    public double cost()
    {
        return cost;
    }
    @Override
    public String toString()
    {
        return "This is Engine object from: "
            + company;
    }
}

轮胎。Java
public class Tyres {

    String name;
    String place;
    String message;

    public String getName()
    {
        return name;
    }
    public void setName(String name)
    {
        this.name = name;
    }
    public String getPlace()
    {
        return place;
    }
    public void setPlace(String place)
    {
        this.place = place;
    }
    public String getMessage()
    {
        return message;
    }
    public void setMessage(String message)
    {
        this.message = message;
    }

    @Override
    public String toString()
    {
        return "This is Tyre object: "
            + name + " " + place
            + " " + message;
    }
}

车辆。Java
public class Vehicle {

    IEngine engine;
    Tyres tyre;

    public Tyres getTyre()
    {
        return tyre;
    }

    public void setTyre(Tyres tyre)
    {
        System.out.println("tyre instantiated via setter");
        this.tyre = tyre;
    }

    public Vehicle(IEngine engine, Tyres tyre)
    {
        System.out.println("instantiated via constructor");
        this.engine = engine;
        this.tyre = tyre;
    }

    public Vehicle() {}
    public IEngine getEngine()
    {

        return engine;
    }
    public void setEngine(IEngine engine)
    {
        System.out.println("instantiated via setter");
        this.engine = engine;
    }

    @Override
    public String toString()
    {
        return engine + " " + tyre;
    }

    public static void main(String a[])
    {
        ApplicationContext rootctx
            = new ClassPathXmlApplicationContext(
                "springContext.xml");

        // Instantiating the obj1 via Constructor DI
        Vehicle obj1
            = (Vehicle)rootctx
                  .getBean("InjectwithConstructor");

        // Instantiating the obj1 via Setter DI
        Vehicle obj2
            = (Vehicle)rootctx
                  .getBean("InjectwithSetter");

        System.out.println(obj1);
        System.out.println(obj2);
        System.out.println(obj1 == obj2);
    }
}

springContext.xml
< bean id="tyre1Bean" class="com.techgene.Tyres">
    
    

    
    

    
    



< bean id="ToyotaBean" class="com.techgene.ToyotaEngine">
    
    

    
    



< bean id="tyre2Bean" class="com.techgene.Tyres">
    
    

    
    

    
    



< bean id="InjectwithSetter" class="com.techgene.Vehicle">
    
    

    
    



< bean id="InjectwithConstructor" class="com.techgene.Vehicle">