prosource

스프링 @프로퍼티 자동배선 vs 컨스트럭터

probook 2023. 3. 9. 22:09
반응형

스프링 @프로퍼티 자동배선 vs 컨스트럭터

Spring을 사용하고 있기 때문에 종속성이 있는 서비스를 작성하면 다음과 같이 합니다.

@Component
public class SomeService {
     @Autowired private SomeOtherService someOtherService;
}

동일한 목표를 달성하기 위해 다른 규칙을 사용하는 코드를 발견했습니다.

@Component
public class SomeService {
    private final SomeOtherService someOtherService;

    @Autowired
    public SomeService(SomeOtherService someOtherService){
        this.someOtherService = someOtherService;
    }
}

두 가지 방법 모두 효과가 있습니다, 이해합니다.하지만 옵션 B를 사용하면 어떤 이점이 있나요?저에게는 클래스 및 유닛 테스트에서 더 많은 코드가 생성됩니다.(컨스트럭터를 작성해야 하고 @InjectMocks를 사용할 수 없음)

제가 놓친 게 있나요?유닛 테스트에 코드를 추가하는 것 외에 자동 배선 컨스트럭터가 수행하는 것이 있습니까?이것이 의존성 주입에 더 적합한 방법입니까?

네, 필드 주입보다 옵션B(컨스트럭터 주입이라고 함)가 실제로 권장되며 다음과 같은 장점이 있습니다.

  • 의존관계가 명확하게 식별된다.테스트 시 또는 기타 상황에서 오브젝트를 인스턴스화할 때 (config 클래스에서 명시적으로 bean instance를 작성하는 등) 하나를 잊어버리는 방법은 없습니다.
  • 의존성은 최종적일 수 있으며, 이는 견고성과 스레드 안전성에 도움이 된다.
  • 종속성을 설정하기 위해 반성이 필요하지 않습니다.Inject Mocks는 계속 사용할 수 있지만 필수는 아닙니다.직접 mock을 만들고 제작자에게 전화하기만 하면 됩니다.

봄의 기고자 중 한 명인 Olivier Gierke의 자세한 기사는 이 블로그 포스트를 참조하십시오.

간단한 말로 설명하겠습니다.

옵션(A)에서는 기본 생성자를 사용하여 인스턴스(예:new SomeService() 않습니다.SomeOtherService로서의) SomeService.

유닛 테스트에 코드를 추가하는 것 외에 자동 배선 컨스트럭터가 수행하는 것이 있습니까?이것이 의존성 주입에 더 적합한 방법입니까?

옵션(B)은 다음을 생성할 수 없기 때문에 권장되는 접근법입니다.SomeService SomeOtherService★★★★★★ 。

Spring 4.3 이후로는 컨스트럭터에 @Autowired가 필요 없기 때문에 Spring 주석과 연결하는 대신 Java 스타일로 코드를 작성할 수 있습니다.스니펫은 다음과 같습니다.

@Component
public class SomeService {
    private final SomeOtherService someOtherService;

    public SomeService(SomeOtherService someOtherService){
        this.someOtherService = someOtherService;
    }
}

알기 좋은.

컨스트럭터 콜이 1개뿐인 경우 @Autowired 주석을 포함할 필요가 없습니다.그런 다음 다음과 같은 것을 사용할 수 있습니다.

@RestController
public class NiceController {

    private final DataRepository repository;

    public NiceController(ChapterRepository repository) {
        this.repository = repository;
    }
}

... Spring Data Repository 주입의 예.

、 、 、 、 、 두째번요요 。★★★ @Autowired 사실 프레임워크너무 밀접하게 결합되지 않은 코드만드는 것이 더 현명하다(스프링만큼 좋다).가능한 한 지연된 의사 결정 방식을 채택하는 코드를 원합니다.그것은 가능한 한 많은 pojo이며, 틀을 쉽게 바꿀 수 있습니다.따라서 별도의 Config 파일을 만들고 다음과 같이 bean을 정의하는 것이 좋습니다.

SomeService.java 파일:

public class SomeService {
    private final SomeOtherService someOtherService;

    public SomeService(SomeOtherService someOtherService){
        this.someOtherService = someOtherService;
    }
}

ServiceConfig.java 파일:

@Config
public class ServiceConfig {
    @Bean
    public SomeService someService(SomeOtherService someOtherService){
        return new SomeService(someOtherService);
    }
}

실제로 자세한 기술을 알고 싶다면 필드 인젝션(Field Injection)을 사용할 때 발생하는 스레드 안전성 문제가 있습니다.@Autowired프로젝트 규모에 따라 달라집니다.자동 배선의 장점과 단점에 대한 자세한 내용은 여기를 참조하십시오.실제로 중요한 사람들은 필드 주입 대신 컨스트럭터 주입을 사용할 것을 권장합니다.

의견표현으로 다운그레이드되지 않았으면 좋겠지만 옵션A는 스프링 의존성 주입의 힘을 더 잘 반영하고 옵션B에서는 클래스를 의존성과 결합합니다.실제로 오브젝트의 인스턴스화는 컨스트럭터로부터 의존성을 전달받지 않고는 할 수 없습니다.Dependency Injection은 Inversion of Control을 구현함으로써 그것을 피하기 위해 발명되었습니다. 그래서 옵션 B는 의미가 없습니다.

Autowired생성자는 스프링 컨테이너에 등록하기 전에 사용자 지정 코드를 추가할 수 있는 후크를 제공합니다.가정하다SomeService는 클래스라는 의 다른 클래스를 합니다.SuperSomeService이치노 「」는,Autowired이치노또한 초기화할 다른 멤버가 있는 경우 인스턴스를 스프링 컨테이너로 반환하기 전에 생성자에서 초기화할 수 있습니다.

public class SuperSomeService {
     private String name;
     public SuperSomeService(String name) {
         this.name = name;
     }
}

@Component
public class SomeService extends SuperSomeService {
    private final SomeOtherService someOtherService;
    private Map<String, String> props = null;

    @Autowired
    public SomeService(SomeOtherService someOtherService){
        SuperSomeService("SomeService")
        this.someOtherService = someOtherService;
        props = loadMap();
    }
}

속성 주입을 사용하여 속성을 주입할 때 불가능한 최종 의존성표시할 수 있기 때문에 건설 주입을 선호합니다.

의존관계는 최종적인 것으로 합니다.즉, 프로그램에 의해서 수정되지 않습니다.

하는 경우는 거의 없다@Autowired가 바람직합니다.그 중 하나는 순환 의존이다.다음과 같은 시나리오를 상정합니다.

@Service
public class EmployeeService {
    private final DepartmentService departmentService;

    public EmployeeService(DepartmentService departmentService) {
        this.departmentService = departmentService;
    }
}

그리고.

@Service
public class DepartmentService {
    private final EmployeeService employeeService;

    public DepartmentService(EmployeeService employeeService) {
        this.employeeService = employeeService;
    }
}

그러면 춘두공장은 순환 의존 예외를 던질 것이다.를 사용하면 이런 일이 일어나지 않습니다.@Autowired두 콩 모두 주석입니다.이것은 이해할 수 있습니다.컨스트럭터 주입은 Spring Bean 초기화 초기 단계에서 이루어집니다.createBeanInstance빈팩토리의 방법,@Autowired- 기반 주입은 훨씬 나중에 후 처리 단계에서 이루어지며 다음과 같이 수행됩니다.AutowiredAnnotationBeanPostProcessor순환 의존성은 복잡한 Spring Context 어플리케이션에서 매우 일반적이며, 단순히 두 개의 콩이 서로 참조하는 것이 아니라 여러 개의 콩으로 이루어진 복잡한 체인이 될 수 있습니다.

다른 입니다.@Autowired매우 도움이 되고, 자제심이 강합니다.

@Service
public class EmployeeService {
    
    @Autowired
    private EmployeeService self;

}

이것은 같은 빈 에서 권장되는 메서드를 호출하기 위해 필요할 수 있습니다.자기주입도 여기서나 여기서논의됩니다.

Lombok의 @RequiredArgsContractor 주석을 사용하여 컨스트럭터를 통해 종속성을 주입하는 방법이 있습니다.

@RequiredArgsConstructor
@Service
 class A {
     private final B b // needs to be declared final to be injected
}

이렇게 하면 생성자를 지정할 필요가 없습니다.

언급URL : https://stackoverflow.com/questions/40620000/spring-autowire-on-properties-vs-constructor

반응형