1. 제어의 역전(Inversion of Control) 정의 및 예제
2. 의존성 주입(Dependency Injection) 정의 및 예제
객체의 의존성을 역전시켜 객체 간의 결합도를 줄이고 유연한 코드를 작성하게 하여 가독성 및 코드의 중복, 유지보수를 편하게 할 수 있게 한다.
아래 코드는
"MyLunch" 클래스에서 "Apple" 객체를 불러오는 예제이다.
일반적으로 의존성에 대한 제어권은 객체 자기 자신에 갖는다.
class MyLunch{
private Apple apple = new Apple();
}
위에 코드에서는 Apple 객체의 제어권이 MyLunch에게 있었다면,
다음 코드에서는 Mylunch에게 Apple의 제어권을 갖고 있는 게 아니라
MyLunchTest에게 있다. 이 처럼 의존성을 역전시켜 제어권을 직접 갖지 않는 것을
Ioc라고 하며, 의존성을 외부에게 주입시켜 주는 것을 DI라고 한다.
class MyLunch{
private Apple apple;
public MyLunch(Apple apple){
this.apple = apple;
}
}
class MyLunchTest{
Apple apple = new Apple();
MyLunch mylunch = new MyLunch(apple);
}
의존성 주입(DI)이란 스프링이 다른 프레임워크와 차별화되어 제공하는 의존 관계 주입 기능으로, 객체를 직접 생성하는 게 아니라 외부에서 생성한 후 주입시켜주는 방식이다. DI를 통해서 모듈 간의 결합도가 낮아지고 유연성이 높아진다.
public class Hello{
public static void main(String[] args){
SayHelloTest sayhellotest = new SayHelloTest();
sayhellotest.sayEn("DI");
}
}
public class SayHelloTest{
public void sayEn(String str){
System.out.println("Hello " + str + "." )
}
}
위에 두 코드를 예시로 설명하자면,
"Hello" 클래스를 실행시키면 "SayHelloTest" 클래스에서 "say" 메서드를 호출한다.
실행 결과로는 "Hello DI."라는 결과를 갖게 될 것이다.
하지만 "Hello DI."라는 결과는 뭔가 딱딱한 거 같다.
뒤에 끝맺음을 마침표로 하지 말고 느낌표로 바꾸어 보자.
그리고 나는 영어만 보면 울렁증이 생긴다.
😔
그렇기 때문에 Hello 가 아닌 "안녕"이라는 말로 바꾸어 출력해 보자.
그리고 한글 버전으로 바꾸기 때문에 클래스 명도 kr로 붙여서 구분하자.
public class Hello{
public static void main(String[] args){
SayHelloTest sayhellotest = new SayHelloTest();
sayhellotest.sayKr("DI");
}
}
public class SayHelloTest{
public void sayKr(String str){
System.out.println("안녕 " + str + "!" )
}
public void sayEn(String str){
System.out.println("Hello " + str + "." )
}
}
SayHelloTest를 다음과 같이 바꾸면 출력 값은 "안녕 DI!"이다.
필자는 영어를 못하고 딱딱한 느낌을 없애기 위하여
SayHelloTest를 수정해야만 했다.
이런 경우 Hello 클래스는 SayHelloTest에 의존성을 가지고 있다고 한다.
Hello 클래스의 기능을 바꾸고자 할 때 SayHelloTest도 함께 바꿔줘야 한다.
기능이 추가될 때마다 매번 코드를 변경해야 하고, 다시 컴파일하는 것은 비용이 많이 들게 된다. 가급적이면 코드의 변화가 적어지도록 프로그램을 작성하는 게 유지 보수 측면에서 유용하게 된다. 이러한 의존성 문제를 해결해주기 위해서 객체의 인스턴스를 외부에서 생성받을 필요가 있다.
의존성 주입 방법
1. 생성자를 이용한 방법(생성자 주입)
생성자 주입 방식은 권장되는 방식으로 생성자 호출 시점에 1회 호출되는 것이 보장된다. 필수적으로 사용하는 매개변수 없이는 인스턴스를 만들 수 없기에 반드시 객체의 주입이 필요한 경우에 강제하기 위해 사용할 수 있다.
@Service
public class Hello{
private SayHelloTest sayhellotest;
@Autowired
public Hello(SayHelloTest sayhellotest){
this.sayhellotest = sayhellotest;
}
...
}
2. Field변수를 이용한 방법
필드 주입 방식은 필드 앞에 @Autowired 어노테이션을 명시한다. 필드 주입 방법으로 사용하면 주입한 것을 중간에 바꿀 수 있는 방법이 없다. 주입되는 변수를 private로 선언하기 때문에 이후 외부 접근도 불가능하다. 따라서 권장하지 않는 방법이다.
@Service
public class Hello{
@Autowired
private SayHelloTest sayhellotest;
...
}
3. setter를 이용한 방법
setter함수에 @Autowired 어노테이션을 명시한다. "sayhellotest"는 prviate으로 선언하고, 이후 setter함수가 호출되어 "sayhellotest"가 주입된다. setter 주입 사용 시 setter 함수가 public으로 노출되어 있어서, "sayhellotest"가 변경될 수 있는 환경이 된다. 외부에서도 얼마든지 Hello.setSayHelloTest()를 호출할 수 있다. 즉 주입받는 객체가 변경될 가능성이 있는 경우에 사용한다.
@Service
public class Hello{
private SayHelloTest sayhellotest;
@Autowired
public void setSayHelloTest(SayHelloTest sayhellotest){
this.sayhellotest = sayhellotest;
}
...
}
'Framework > Spring' 카테고리의 다른 글
[Spring] 롬복 어노테이션(@NoArgsConstructor, @RequiredConstructor, @AllArgsConstruct)에 대해서 - 컴도리돌이 (0) | 2024.03.20 |
---|---|
[Spring] @RequestMapping 어노테이션에 대해서 - 컴도리돌이 (0) | 2023.11.27 |
[Spring] @SpringBootApplication의 내부적으로 수행하는 작업 - 컴도리돌이 (4) | 2023.07.22 |
[Spring][Security] 스프링 시큐리티(Spring Security)에 대해서 - 스프링 시큐리티 아키텍처, 필터 - 컴도리돌이 (0) | 2022.08.15 |
[Spring] 스프링 빈(Bean)에 대해서 - 컴도리돌이 (0) | 2022.07.22 |