의존성 주입

kangking·2024년 6월 19일
0

Spring Boot

목록 보기
2/10

의존성 주입

의존성 주입(Dependency Injection, DI)은 소프트웨어 설계 원칙 중 하나로, 객체 지향 프로그래밍에서 객체의 생성과 객체 간의 의존성을 설정하는 과정을 분리하는 방법이다.

객체가 다른 객체를 필요로 할 때 새로 생성하기 보단, 기존에 있던 객체로부터 의존성을 주입시켜 객체간 결합도를 낮춘다.

용어

  • 의존성(Dependency)

    한 객체가 필요로 하는 다른 객체를 의미

    클래스 A가 클래스 B의 기능을 사용해야 하는 경우, B는 A의 의존성

  • 주입(Injection)

    의존성을 외부에서 제공하는 과정으로, 객체 A가 객체 B를 필요로 할 때 객체 B를 생성하고 A에 전달하는 과정을 의미한다.

의존성 주입의 방법

  • 필드 주입: 변수에 @Autowired

    컴파일할 때 순환 참조 에러를 찾지 못하고 그 부분이 실행될 때 찾음

  • setter주입: 메소드에 @Autowired

    자바의 다형성을 이용해서 하나의 변수에 여러 객체를 저장할 수 있는데, setter에 의해서 의존성 주입받은 객체가 바뀔 수 있음

  • 생성자 주입: 생성자로 받아서 주입 (가장 바람직)

    컴파일할 때부터 순환 참조 에러를 찾을 수 있음
    (Spring 4.3버전 이후부턴 생성자에 @Autowired 생략가능)

장점

  • 결합도 감소

    객체가 다른 객체를 직접 생성하지 않고 외부에서 주입받기 때문에 클래스 간의 결합도가 낮아지며, 이는 코드의 유연성을 높이고, 변경에 더 잘 대응할 수 있게 한다.

  • 재사용성 증가

    의존성을 외부에서 주입받기 때문에 동일한 클래스를 다양한 컨텍스트에서 재사용할 수 있다.

  • 테스트 용이성

    의존성을 외부에서 주입받기 때문에, 단위 테스트 시 모의 객체(Mock Object)를 쉽게 주입하여 테스트할 수 있다.

순환 참조

두 개 이상의 빈이나 객체가 서로를 의존하는 상황을 의미하며 실행이나 컴파일 시 장애를 일으킬 수 있는 요인

예시 코드

  • Bean이 생성될 때, A는 B를 참조하고, 동시에 B는 A를 참조하는 경우(생성자로 주입)

    @Component
    public class A {
        private final B b;
    
        @Autowired
        public A(B b) {
            this.b = b;
        }
    }
    
    @Component
    public class B {
        private final A a;
    
        @Autowired
        public B(A a) {
            this.a = a;
        }
    }

    생성자로 의존성을 주입하게 되면 위의 코드일 경우 @Component가 붙은 클래스를 Bean으로 객체 생성 시도하는 시점(component-scan때 생성자를 호출하는 시점)에 무한 루프에 빠질 수 있다.

    Bean A를 생성하려면 Bean B가 필요하고, Bean B를 생성하려면 Bean A가 필요한 상황이 발생하기 때문에 정상적으로 애플리케이션이 실행되지 못하고 문제가 발생하게 된다.

    즉, 생성자로 의존성을 주입하게 되면 컴파일 시점에서 순환참조가 발생했음을 알 수 있다.

  • 필드에서 @Autowired로 주입시

    우선 객체 또는 Bean이 생성되고 런타임 시점에서 호출시 에러가 발생할 수 있음

해결방안

어떤 방법이든 임시방편이기 때문에 구조 자체를 다시 짜는 것이 정론이다.

왜 써야하는가?

초기 개발시 고려할 점이 많아진다는 점에선 부정적 측면을 가지고 있다.

하지만 개발하려는 서비스의 규모를 확장하거나 이미 충분히 큰 규모의 서비스라면 유지보수나 테스트의 용의성, 확장성 등의 장점 때문에 사실상 필수 불가결한 선택이다.

profile
하루하루 의미있게

0개의 댓글