의존성 주입(DI)

2023-04-27
ꞏ
유영진
ꞏ
show5116

DI(Dependency Injection)는 의존성 주입으로, 하나의 객체가 다른 객체의 의존성을 제공하는 기술입니다.
클래스 레벨에서는 의존관계가 고정되지 않고 런타임 시에 관계를 동적으로 주입해주어서,
유연성을 확보하고 결합도를 낮출 수 있게 해줍니다.

의존성 주입 방법

Spring에서 의존성을 주입하는 방법에는 3가지가 있습니다.
결론부터 말하면 생성자 주입 방법을 사용하는 것이 좋습니다.

생성자 주입

java
1@Controller
2public class ExampleController {
3 private final ExampleService1 service1;
4 private final ExampleService2 service2;
5
6 // Class내 생성자가 하나뿐이면 @Autowired 생략 가능
7 @Autowired
8 public ExampleController(ExampleService1 service1, ExampleService2 service2) {
9 this.service1 = service1;
10 this.service2 = service2;
11 }
12}

생성자 주입은 생성자 호출 시점에 1회 호출 되는 것이 보장되어서, 주입받은 객체가 변하지 않게 됩니다.

필드 주입

java
1@Controller
2public class ExampleController {
3 @Autowired
4 private final ExampleService1 service1;
5 @Autowired
6 private final ExampleService2 service2;
7}

필드 주입은 코드가 간결해지고 유지보수가 편해지는 장점이 있습니다.
하지만 외부에서 접근이 불가능하다는 단점이 있습니다.
또한 반드시 Spring과 같은 DI 프레임워크가 존재해야 하기 때문에 사용을 지양합니다.

Setter 주입

java
1@Controller
2public class ExampleController {
3 private final ExampleService1 service1;
4 private final ExampleService2 service2;
5
6 @Autowired
7 public void setService1(ExampleService1 service1) {
8 this.service1 = service1;
9 }
10
11 @Autowired(required = false)
12 public void setService2(ExampleService2 service2) {
13 this.service2 = service2;
14 }
15}

Setter 주입은 생성자 주입과 다르게 주입받는 객체가 변경될 가능성이 있는 경우에 사용합니다.
@Autowired 어노테이션은 주입할 대상이 없는 경우에는 오류가 발생합니다.
따라서 주입할 대상이 없어도 동작하도록 하려면 requried = false를 이용해 설정할 수 있습니다.

Lombok 활용

생성자 주입은 필드 객체에 final 키워드를 사용할 수 있습니다.
Lombok의 @RequiredArgsConstructor를 활용하면,
final 변수를 위한 생성자를 대신 생성해줍니다.
이를 활용하면 새로운 객체를 추가하거나 기존 객체를 삭제할 때 등등…
유지보수가 간결해지며 코드 작성시에도 간편해집니다.

java
1// 변경 전
2@Controller
3public class ExampleController {
4 private final ExampleService1 service1;
5 private final ExampleService2 service2;
6
7 public ExampleController(ExampleService1 service1, ExampleService2 service2) {
8 this.service1 = service1;
9 this.service2 = service2;
10 }
11}
12
13// 변경 후
14@RequiredArgsConstructor
15@Controller
16public class ExampleController {
17 private final ExampleService1 service1;
18 private final ExampleService2 service2;
19}

변경 전과 변경 후의 코드가 동일한 생성자 주입을 하는 코드가 됩니다.
코드 작성이 편해지면서 수정이 적어집니다.