IT/WEB

[Spring] @Autowired

개발자 두더지 2023. 7. 9. 16:15
728x90

일본의 한 블로그 글을 번역한 포스트입니다. 오역 및 의역, 직역이 있을 수 있으며 틀린 내용은 지적해주시면 감사하겠습니다.

 

 이번 포스트에서는 Spring 프레임워크에서 이용되는 @Autowired의 인젝션 종류에 대해서 살펴보자. Spring을 거의 만져 본 경험이 없는 사람들을 위한 내용이 될 것이다.

 

@Autowired이란?


 간단히 말하자면, 사용하고자하는 클래스의 인스턴스화해주는 어노테이션이다. 기재하는 것으로 클래스 내 New연산자없이 인스턴스화를 한 번에 할 수 있다는 장점이 있다.

public class HogeClass{

@Autowired
private HugaService hugaService;

...
}

 예로 설명하자면 어노테이션을 사용하는 것으로 클래스 내의 HogeService의 처리를 호출할 수 있게 된다. 그러나 @Autowired에 인스턴스화를 맡길 수 있는 것은 Spring 프레임워크가 제공하고 있는 DI컨테이너에 등록되어 있는 클래스만 가능하다.

 DI 컨테이너로 등록하기 위해서는 @Component, @Controller, @Service, @Repositroy과 같은 어노테이션이 붙어 있어야한다. 

 

 

@Autowired에 의한 인젝션 종류


 그럼 본론으로 들어가서 @Autowired에 의한 인젝션의 종류에 대해서 알아보자. 인젝션의 기법은 크게 세 가지가 있다.

  • 필드 인젝션(비추천 )
  • 세터 인젝션
  • 컨스트럭터 인젝션(추천)

 

필드 인젝션

public class HogeClass{

@Autowired
private HugaService hugaService;
private HugaHugaService hugahugaService;

...
}

 세 가지 인젝션 기법중에 가장 간단히 인젝션할 수 있으므로 사용하는 사람들이 많다. 그러나, 이것은 Spring에서는 비추천되는 기법이므로 주의할 필요가 있다. 이유에 대해서는 나중에 설명하도록 하겠다.

 

세터 인젝션

public class HogeClass{

private final HugaService hugaService;
private final HugaHugaService hugaHugaService;

@Autowired
public setHugaService(HugaService hugaService){
    this.hugaService = hugaService;
}

@Autowired
public setHugaHugaService(HugaHugaService hugaHugaService){
    this.hugaHugaService = hugaHugaService;
}

...
}

 이 방법은 bean설정용의 setter를 @Autowired에 부여하여 정의하는 방법이다. 추천/비추천에 대해 명확하게 명시된 것이 없지만, setter을 사용하는 성질상, 컨스트럭터 호출후에 바뀔 가능성이 있으므로 상태 전이가 있는 클래스/메소드가 되어 불안정해지기 쉽기 때문에 다른 방법에 비해서는 사용되지 않는 것 같다.

 

 

컨스트럭터 인젝션

public class HogeClass{

private final HugaService hugaService;
private final HugaHugaService hugahugaService;

@Autowired
public HogeClass(HugaService hugaService){
    this.hugaService = hugaService;
    this.hugahugaService = hugahugaService;
}

...
}

 이 컨스트럭터 인젝션이 Spring에서 추천하는 인젝션 방법이 된다. 방금 봤던 필드 인젝션에 비해서 써야할 코드가 늘어 왜 간단한 기재법으로는 안되는 것인가에 대해서 의문이 들 수 있는데 조금 더 인내심을 가지고 계속해서 읽어주길 바란다.

 

 

왜 컨스트럭터 인젝션이 추천되는 것인가?


 그럼 계속해서 의문을 가졌을 컨스트럭트 인젝션이 추천되는 이유에 대해서 설명하도록 하겠다. 컨스트럭트 인젝션이 추천되는 것에 대해 다양한 관점들이 있지만, 개인적으로는 아래의 세 가지가 가장 큰 이유라고 생각한다.

 

단일책임의 원칙

 오브젝트 지향 언어에 있어서 설계 원리의 하나로 SOLID원칙이라는 것이 있다. 단일 책임의 원칙이란 "SOLID원칙"의 안에서 제창된 원리의 하나로 간단히 얘기하자면, 1개의 클래스는 하나의 책임(기능)을 가져야만한다는 것이다.

 컨스트럭트 인젝션이 번잡하게 느껴지는 경우, 그 클래스는 수 많은 기능을 인젝션하고 있는(=의존관계가 많은) 것이 된다. 

 즉 단일 책임의 원리에서 본다면 위와 같은 클래스는 "1개의 클래스가 많은 책임을 가지고 있는것"이므로 원리에 반하게 된다. 컨스트럭터 인젝션을 이용하면 이러한 원칙에 위배되고 있음을 금방 알게 된다.

 

컨스트럭터가 불변성을 가질 수 있게 됨

 컨스트럭터 인젝션을 하는 것으로 필드를 final로 선언하는 것이 가능하다. 이로인해 불변객체로 하거나, 필요한 의존관계만을 변하지 않도록 할 수 있다.

 필드 인젝션의 경우, final 선언이 안되므로 의존관계가 변할 가능성이 있다.

 

순환 의존을 방지할 수 있다.

 컨스트럭터 인젝션에서 final 선언하고 있는 경우, 컨스트럭터 호출의 타이밍에서 DI의 설정을 완료하고, 그 후에 앞서 설명했던 대로 불변객체가 된다. 그러므로 순환 의존이 일어나고 있는 경우, 어플리케이션 실행시에 경고가 나타난다.

 다른 두 가지 인젝션에 애대해서는 실제로 대상의 DI 컨터네이너가 호출될때가지는 문제를 검지하는 것이 힘들다.


참고자료

https://qiita.com/yuto-hatano/items/69d01343f710117e4243

728x90