programing

시공자 주입이 다른 옵션보다 우수한 이유 설명

codeshow 2023. 9. 9. 10:19
반응형

시공자 주입이 다른 옵션보다 우수한 이유 설명

프로 스프링 3권 4장 - IOC와 DI in Spring - 59페이지 "세터 인젝션 vs.시공자 주입" 섹션에 다음과 같이 기술되어 있습니다.

스프링 포함, Setter Injection을 사용할 때 모든 종속성이 정의되도록 보장하는 메커니즘을 제공하지만 Constructor Injection을 사용하면 컨테이너에 구애받지 않는 방식으로 종속성에 대한 요구 사항을 주장합니다."

예를 들어 설명해 주시겠습니까?

필수 종속성을 생성자 인수로 사용하는 클래스는 해당 인수가 제공된 경우(인수가 null이 아닌지 확인하려면 보호 절이 있어야 함)(또는 Kotlin에서 null이 아닌 유형을 사용함)에만 인스턴스화할 수 있습니다.따라서 시공자는 Spring을 사용하는지 여부에 관계없이 종속성 요구 사항을 적용하므로 컨테이너에 구애받지 않습니다.

setter injection을 사용하는 경우 setter가 호출되거나 호출되지 않을 수 있으므로 인스턴스에 종속성이 제공되지 않을 수 있습니다.은 setter를 사용하는 입니다.@Required아니면@Autowired에 구애받지 즉,로에지다만다지에만h로rse-,tds .

따라서 코드를 Spring과 독립적으로 유지하려면 주입에 생성자 인수를 사용합니다.이는 테스트에 적용됩니다. 응용프로그램 컨텍스트를 구성하거나 통합 테스트 설정에 따라 발생하는 복잡성 없이 일반 단위 테스트에서 클래스를 인스턴스화하고 테스트하는 데 더 용이합니다.

업데이트: Spring 4.3은 단일 컨스트럭터 시나리오에서 암시적 인젝션을 수행하므로 잠재적으로 코드가 필요하지 않음으로써 Spring으로부터 더욱 독립적으로 코드를 생성합니다.@Autowired주석 따위는 전혀 없습니다.

(...) 생성자 주입(Constructor Injection)을 사용하여 컨테이너에 무관한 방식으로 종속성에 대한 요구 사항을 주장합니다.

, 컨테이너별 솔루션을 사용하지 않고 주입된 모든 필드에 대한 요구 사항을 적용할 수 있습니다.


설정자 주입 예제

특수 포함 @Required필요합니다.

@필수

메서드(일반적으로 Java Bean setter 메서드)를 '필수'로 표시합니다. 즉, setter 메서드는 종속성을 값으로 주입하도록 구성해야 합니다.

사용.

import org.springframework.beans.factory.annotation.Required;

import javax.inject.Inject;
import javax.inject.Named;

@Named
public class Foo {

    private Bar bar;

    @Inject
    @Required
    public void setBar(Bar bar) {
        this.bar = bar;
    }
}

생성자 주입 예제

모든 필수 필드는 생성자 순수 Java 솔루션에 정의됩니다.

사용.

import javax.inject.Inject;
import javax.inject.Named;

@Named
public class Foo {

    private Bar bar;

    @Inject
    public Foo(Bar bar) {
        this.bar = bar;
    }

}

단위시험

이는 단위 테스트에서 특히 유용합니다.그런 종류의 테스트는 매우 간단해야 하며 주석을 이해하지 못합니다.@Required를 실행하기 , 를 하기 이 하지 으로 하지 이 으로 컨스트럭터를 사용하면 테스트를 위한 이 클래스의 설정이 훨씬 쉬워지므로 테스트 중인 클래스가 어떻게 구현되는지 분석할 필요가 없습니다.

간단히 말하면 필수 종속성의 경우 생성자 기반 종속성 주입을 사용하고 선택적 종속성의 경우 설정자 기반 주입을 사용할 수 있습니다.그것은 경험칙입니다!!

예를 들면요.

클래스를 인스턴스화하려면 항상 클래스 생성자를 사용합니다.따라서 생성자 기반 주입을 사용하는 경우 클래스를 인스턴스화할 수 있는 유일한 방법은 해당 생성자를 통해서입니다.생성자를 통해 종속성을 전달하면 종속성이 필수 종속성임이 분명합니다.

반면 POJO 클래스에 setter 메서드가 있는 경우 해당 setter 메서드를 사용하여 클래스 변수의 값을 설정하거나 설정하지 않을 수 있습니다.이것은 전적으로 당신의 필요에 따라 결정됩니다. 즉, 선택 사항입니다.따라서 클래스의 setter 메서드를 통해 종속성을 전달하면 이는 암묵적으로 선택적 종속성임을 의미합니다.이상 없으시길 바랍니다!!

종속 클래스가 없으면 클래스가 작동할 수 없을 때 생성자 주입을 사용합니다.

속성 주입은 종속 클래스 없이 클래스가 작동할 수 있을 때 사용됩니다.

구체적인 예로 IS 서비스에 의존하여 업무를 수행하는 Service Repository를 생각해 보십시오.ServiceRepository는 IS 서비스 없이는 유용하게 작동할 수 없으므로 생성자를 통해 주입하는 것이 좋습니다.

동일한 ServiceRepository 클래스에서 Logger를 사용하여 추적 작업을 수행할 수 있습니다.ILogger는 Property injection(속성 주입)을 통해 주입할 수 있습니다.

속성 주입의 다른 일반적인 예로는 ICache(AOP 용어의 다른 측면) 또는 IBaseProperty(기본 클래스의 속성)가 있습니다.

Constructor Injection을 사용하면 컨테이너에 구애받지 않는 방식으로 종속성에 대한 요구 사항을 주장할 수 있습니다.

우리는 IoC 용기에서 콩을 사용하기 전에 필요한 콩을 주입해야 한다는 확약이 필요합니다.

세터 인젝션 전략에서, 우리는 IoC 용기가 먼저 콩을 만들 것이지만 세터 방법으로 콩을 사용하기 직전에 인젝션을 할 것이라고 믿습니다.그리고 주사는 당신의 구성에 따라 이루어집니다.구성에 주입할 콩을 지정하지 않은 경우 해당 콩에 대해 주입이 수행되지 않으며 의존 콩이 언제 사용되는지에 따라 기능하지 않습니다!

그러나 컨스트럭터 주입 전략에서 컨테이너는 콩을 제조하는 동안 의존성을 적절하게 제공하기 위해 부과(또는 부과)합니다.이 문제는 "컨테이너에 구애받지 않는 방식"으로 해결되었는데, 우리는 빈을 생성하는 동안 의존성을 제공해야 하기 때문에 IoC 컨테이너와는 독립적으로 의존성의 가시성을 확보해야 하기 때문입니다.

편집:

Q1: 그리고 시공자가 콩을 만드는 것을 방지하는 방법null콩을 놓치는 대신에 가치를?

당신은 그 어떤 것도 정말로 놓칠 수 없습니다.<constructor-arg>(Spring의 경우), IoC 컨테이너에 의해 빈을 생성하기 위해 제공된 생성자와 일치시키는 데 필요한 모든 생성자 인수를 제공해야 하기 때문입니다.제공하는 경우null당신의<constructor-arg>고의로그렇다면 IoC 컨테이너가 할 수도 필요도 없습니다!

이 예는 다음과 같은 도움이 될 수 있습니다.

컨트롤러 클래스:

@RestController
@RequestMapping("/abc/dev")
@Scope(value = WebApplicationContext.SCOPE_REQUEST)
public class MyController {
//Setter Injection
@Resource(name="configBlack")
public void setColor(Color c) {
    System.out.println("Injecting setter");
    this.blackColor = c;
}

public Color getColor() {
    return this.blackColor;
}

public MyController() {
    super();
}

Color nred;
Color nblack;

//Constructor injection
@Autowired
public MyController(@Qualifier("constBlack")Color b, @Qualifier("constRed")Color r) {
    this.nred = r;
    this.nblack = b;
}

private Color blackColor;

//Field injection
@Autowired
private Color black;

//Field injection
@Resource(name="configRed")
private Color red;

@RequestMapping(value = "/customers", produces = { "application/text" }, method = RequestMethod.GET)
@ResponseStatus(value = HttpStatus.CREATED)
public String createCustomer() {
    System.out.println("Field injection red: " + red.getName());
    System.out.println("Field injection: " + black.getName());
    System.out.println("Setter injection black: " + blackColor.getName());

    System.out.println("Constructor inject nred: " + nred.getName());
    System.out.println("Constructor inject nblack: " + nblack.getName());


    MyController mc = new MyController();
    mc.setColor(new Red("No injection red"));
    System.out.println("No injection : " + mc.getColor().getName());

    return "Hello";
}
}

인터페이스 색상:

public interface Color {
    public String getName();
}

빨간색 클래스:

@Component
public class Red implements Color{
private String name;

@Override
public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public Red(String name) {
    System.out.println("Red color: "+ name);
    this.name = name;
}

public Red() {
    System.out.println("Red color default constructor");
}

}

클래스 블랙:

@Component
public class Black implements Color{
private String name;

@Override
public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public Black(String name) {
    System.out.println("Black color: "+ name);
    this.name = name;
}

public Black() {
    System.out.println("Black color default constructor");
}

}

빈을 만들기 위한 구성 클래스:

@Configuration
public class Config {

@Bean(name = "configRed")
public Red getRedInstance() {
    Red red = new Red();
    red.setName("Config red");
    return red;
}

@Bean(name = "configBlack")
public Black getBlackInstance() {
    Black black = new Black();
    black.setName("config Black");
    return black;
}

@Bean(name = "constRed")
public Red getConstRedInstance() {
    Red red = new Red();
    red.setName("Config const red");
    return red;
}

@Bean(name = "constBlack")
public Black getConstBlackInstance() {
    Black black = new Black();
    black.setName("config const Black");
    return black;
}
}

Boot Application(메인 클래스):

@SpringBootApplication
@ComponentScan(basePackages = {"com"})
public class BootApplication {

public static void main(String[] args) {
    SpringApplication.run(BootApplication.class, args);
}
}

애플리케이션을 실행하고 URL을 클릭합니다. GET 127.0.0.1:8080/abc/dev/customers/

Output:
Injecting setter
Field injection red: Config red
Field injection: null
Setter injection black: config Black
Constructor inject nred: Config const red
Constructor inject nblack: config const Black
Red color: No injection red
Injecting setter
No injection : No injection red

예를 들어요?간단한 것은 다음과 같습니다.

public class TwoInjectionStyles {
    private Foo foo;

    // Constructor injection
    public TwoInjectionStyles(Foo f) {
        this.foo = f;
    }

    // Setting injection
    public void setFoo(Foo f) { this.foo = f; }
}

저는 개인적으로 가능할 때 시공자 주입을 더 선호합니다.

두 경우 모두, 콩 공장은 다음과 같은 경우에TwoInjectionStyles그리고.Foo예를 들어 전자에게 그 예를 제시합니다.Foo의존.

언급URL : https://stackoverflow.com/questions/21218868/explain-why-constructor-inject-is-better-than-other-options

반응형