programing tip

속성 대 생성자에 대한 Spring @Autowire

itbloger 2020. 8. 18. 07:25
반응형

속성 대 생성자에 대한 Spring @Autowire


따라서 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를 사용할 수 없음)

내가 놓친 것이 있습니까? 단위 테스트에 코드를 추가하는 것 외에 autowired 생성자가 수행하는 다른 작업이 있습니까? 이것이 종속성 주입을 수행하는 더 선호되는 방법입니까?


예, 옵션 B (생성자 주입이라고 함)는 실제로 필드 주입보다 권장되며 몇 가지 장점이 있습니다.

  • 종속성이 명확하게 식별됩니다. 테스트 할 때 또는 다른 상황에서 객체를 인스턴스화 할 때 하나를 잊을 방법이 없습니다 (구성 클래스에서 명시 적으로 빈 인스턴스를 생성하는 것과 같이).
  • 종속성은 최종적 일 수 있으므로 견고성과 스레드 안전성에 도움이됩니다.
  • 종속성을 설정하기 위해 리플렉션이 필요하지 않습니다. InjectMocks는 여전히 사용할 수 있지만 필요하지는 않습니다. 직접 모의를 만들고 생성자를 호출하여 삽입 할 수 있습니다.

Spring 기고자 중 한 사람인 Olivier Gierke 의 자세한 기사는 이 블로그 게시물참조하십시오 .


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

옵션 (A)에서, 당신은 (Spring 컨테이너 내 다른 클래스 외부에서 /) 사람이 기본 생성자 (같은 사용하여 인스턴스 생성 할 수 있습니다 new SomeService()당신이 필요로 좋지 않다), SomeOtherService당신을 위해 (종속성으로) 객체를 SomeService.

단위 테스트에 코드를 추가하는 것 외에 autowired 생성자가 수행하는 다른 작업이 있습니까? 이것이 종속성 주입을 수행하는 더 선호되는 방법입니까?

Option (B)는SomeService 실제로 SomeOtherService종속성을 해결하지 않고는 개체 를 만들 수 없으므로 선호되는 접근 방식 입니다.


알아 둘만 한

생성자 호출이 하나만있는 경우 @Autowired 주석을 포함 할 필요가 없습니다. 그런 다음 다음과 같이 사용할 수 있습니다.

@RestController
public class NiceController {

    private final DataRepository repository;

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

... 스프링 데이터 리포지토리 주입의 예.


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();
    }
}

Actually, In my experience, The second option is better. Without the need for @Autowired. In fact, it is wiser to create code that is not too tightly coupled with the framework (as good as Spring is). You want code that tries as much as possible to adopt a deferred decision-making approach. That is as much pojo as possible, so much such that the framework can be swapped out easily. So I would advise you create a separate Config file and define your bean there, like this:

In SomeService.java file:

public class SomeService {
    private final SomeOtherService someOtherService;

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

In ServiceConfig.java file:

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

In fact, if you want to get deeply technical about it, there are thread safety questions (among other things) that arise with the use of Field Injection (@Autowired), depending on the size of the project obviously. Check this out to learn more on the advantages and disadvantages of Autowiring. Actually, the pivotal guys actually recommend that you use Constructor injection instead of Field Injection

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

반응형