🚀 DI (Dependency Injection)
: 의존성 주입
A라는 크래스에서 B라는 클래스를 필요로 할 때 A는 B의 의존성을 갖는다고 한다.
의존성 주입을 하면 프로그램 설계를 할 때 코드 재사용성이 향상된다. 객체간의 결합도가 낮아지면서 유연한 코드 작성 가능.
🚀 IoC (Inversion of Control)
제어의 반전이라는 뜻.
근데 why 제어의 반전?
기존 프로그래밍에서의 논리 흐름은, A클래스에서 B클래스를 호출하게 되면, A클래스를 생성하고, 그 다음으로 호출되는 B클래스 객체를 생성한다.
그러나 IoC 의 프로세스에서는 주입 객체로 정의되어있는 클래스들(B클래스)을 먼저 생성하고 그 다음에 호출하는 메인 클래스(A클래스)를 생성하기 때문에 이를 제어의 반전 또는 역행이라고 하는 것이다.
스프링에서 제공하는 IoC Container : 빈(bean)을 만들고 의존성을 엮어주는 일을 한다.
특정한 인터페이스를 상속하거나 빈으로 등록하는 특정 어노테이션이 정의되어있거나(ex. @Controller), 아니면 빈으로 직접 등록하거나의 경우에만 스프링 IoC 컨테이너에 빈으로 등록된다.
이렇게 빈으로 등록된 객체들은 IoC컨테이너가 의존성으로 엮어준다. (기본적으로 의존성 주입은 IoC컨테이너 안에서 빈으로 등록된 객체들만 가능하다. )
🔌 Spring 의존성 주입 방법 3가지
- 생성자 주입
- 세터 주입
- 필드 주입
먼저 DI의 의존성 주입은 Setter 주입, 생성자 주입 두가지가 있다.
✏️ setter 주입
public class Library {
private Novel novel;
public cvoid setNovel(Novel novel){
this.novel = novel
}
public void readNovel(){
novel.subject();
}
}
public interface novel{
void subject();
}
public class NovelImple implements Novel {
@Override
public void subject() {
System.out.println("This Subject is Comics");
}
}
public class Main {
public static void main(String[] args) {
Library library = new Library();
//1.
library.setNevel(new NovelImple());
//2.
library.setNovel(new Novel(){
@Override
public void subject(){
System.out.println("This Subject is Romans");
}
});
// 구현체 주입 후 호출
library.readNovel();
}
}
- setter 주입을 사용하면 구현체의 내부 동작을 알지 못하고 알 필요도 없게 된다.
- Library 클래스의 readNovel() 메서드는 Novel 타입의 객체에 의존하고 있다. But, setter에 주입이 필요한 객체가 주입되지 않아도 객체는 얼마든지 생성할 수 있기 때문에 의존성 주입 없이 readNovel() 메소드에 접근하게 되면 NullPointerExceoption 이 발할 수 있다.
✏️ 생성자 주입
생성자 주입을 하게 된다면 Library 클래스의 setter를 없애고 다음과 같이 생성자로 주입을 하게된다.
public class Library {
private Novel novel;
public Library(Novel novel){
this.novel = novel;
}
public void readNovel(){
novel.subject();
}
}
- 의존관계를 주입하지 않을 시엔 Library 객체를 생성할 수 없기 때문에 NullPointException이 발생할 일이 없다. 컴파일 타임에 오류를 잡아낼 수 있음.
Spring의 의존성주입은 위의 두가지와 더해서 필드주입까지 세 가지의 방법이 있음.
✏️ 필드 주입
public class A implements B {
@Autowired
private B b ;
@Override
public void testMethod(){
b.bMethod();
}
}
필드 주입시 단점
: 순환참조시 StackOverflowError 발생시킴 <- 이는 객체가 모두 생성이 된 후 로직상에서 순환참조가 발생하기 때문에 로직이 구동되기 전 까지 순환참조인지 모른다.
but 생성자 주입으로 이루여질 경우, 빈 생성 시 객체간 순환참조를 하고있는 경우에 다음과 같은 에러메세지와 함께 스프링 어플리케이션이 구동되지 않는다.
Description : The dependencies of some of the beans in the application context form a cycle
why? Aclass와 Bclass가 서로 순환참조 하고있다고 가정ㄹ할 경우에, 생성자 주입시 다음과 같은 로직이 수행된다고 볼 수 있다.
new Aclass(new Bclass(new Aclass(new ... )))
-> 컨테이너가 빈을 생성하는 시점에서 객체생성에 사이클 관계가 생긴다.
https://www.baeldung.com/inversion-control-and-dependency-injection-in-spring
스프링 - 생성자 주입을 사용해야 하는 이유, 필드인젝션이 좋지 않은 이유
🚀 SOLID
SOLID란? 클린코드로 유명한 로버트 마틴이 좋은 객체 지향 설계의 5가지 원칙(SRP, OCP, LSP, ISP, DIP)의 앞 글자를 따서 만든 용어
SRP(Single Responsibility Principle) 단일 책임의 원칙
: 객체는 단 하나의 책임만 가질 수 있다. 객체간의 응집도는 높으며 결합도는 낮은 프로그램을 설계하기 위한 원칙. 한 객체가 다루는 기능 이외의 다른 기능들을 추가하게 된다면 응집도가 낮아지고 메소드간의 결합이 강해질 수밖에 없다.
OCP(Open/Clodes Principle) 개방 폐쇄 원칙
: 다형성을 통한 기능의 확장. 자신의 확장에는 열려있어야 하고 주변에 변화에서는 닫혀있어야 한다.
LSP(Liskov Substitution Principle) 리스코프 치환 원칙
: 클래스를 상속하는 자식 클래스들은 부모 클래스의 규약을 지쳐야 한다.
ISP(Interface Segregation Principle) 인터페이스 분리 원칙
: 클라이언트가 자신이 이용하지 않는 메서드에 의존하면 안된다는 원칙. 인터페이스 분리를 통해 다중상속을 이룬다.
DIP(Dependency Inversion Principle) 의존관계 역전 원칙
: 구현체보다는 인터페이스나 추상 클래스에 의존하는 것이 좋다. 클라이언트가 인터페이스에 의존해야 유연하게 구현체를 변경할 수 있다.
'Dev > Spring' 카테고리의 다른 글
[Spring] AOP(Aspected-Oriented Programming) (0) | 2022.02.05 |
---|---|
[Spring] Singleton / Prototype (0) | 2022.01.17 |
[Spring] 스프링이 빈 스코프를 싱클톤으로 만드는 이유 (0) | 2022.01.17 |
[Spring] Bean 생명 주기 (0) | 2022.01.17 |
[Spring] 빈 등록방법, 의존관계 자동주입, lombok (0) | 2021.12.25 |
댓글