Spring Boot/Spring Core

Spring의 의존성 주입(Dependency Injection)

gigyesik 2024. 4. 4. 03:42
반응형

들어가며

Spring Boot는 객체와 의존성 관리에 Spring Framework의 제어 역전(Inversion of Control. IoC)을 사용한다.

IoC 컨테이너는 객체의 생성, 제어 등 객체의 라이프사이클을 관리한다.

객체가 생성될 때, 객체에 포함된 의존성 또한 주입된다.

Spring의 의존성 주입

의존성 주입(Dependency Injection. DI)은 어플리케이션의 소스코드를 관리하기 쉽도록 의존성 부분을 생략, 제거해주는 디자인 패턴이다.

DI를 사용하면 소스코드의 결합도를 낮출 수 있다.

DI를 이해하기 위해, 의존성 탐색(Dependency Lookup. DL)을 먼저 살펴봐야 한다.

의존성 탐색 (Dependency Lookup)

의존성 탐색은 객체의 리소스에 접근하는 방법을 의미한다. 아래와 같이 다양한 방법으로 리소스에 접근할 수 있다.

A obj = new AImpl(); // new keyword
A obj = A.getA(); // factory method

또한 환경변수와 같은 리소스에는 JNDI(Java Naming Directory Interface)를 사용하여 접근할 수 있다.

Context ctx = new InitialContext();
Context environmentContext = (Context) ctx.lookup("java:comp/env");
A obj = (A) environmentContext.lookup("A");

위와 같이 리소스에 접근할 수 있는 방법은 다양하지만, DL은 단점 또한 존재한다.

의존성 탐색 기법의 단점

  • 코드를 강하게 결합하게(Tight coupling) 만든다. 리소스가 변경될 경우, 리소스가 사용된 소스의 모든 부분을 변경해야 한다.
  • 테스트가 용이하지 않다. 특히 Black Box Testing 에서 객체 생성에 여러 문제점을 갖게 된다.

의존성 주입 (Dependency Injection)

의존성 주입은 소스코드에서 의존성을 제거하는 디자인 패턴이다.

의존성 주입을 사용하면 의존성에 대한 정보를 외부에서 주입받게 되어 결합도를 낮추고 테스트를 용이하게 해준다.

우선 Employee 클래스를 작성한다.

public class Employee {
    Address address;

    public Employee(Address address) {
        this.address = address;
    }
    
    public void setAddress(Address address) {
        this.address = address;
    }
}

위 코드에서 Address는 직접 작성한 것이 아닌 외부에서 주입받은 것이다.

Spring에서 의존성 주입을 구현하는 방법

생성자(Constructor)를 사용하는 방법

public class EmployeeByConstructor {
    private int id;
    private String name;

    public EmployeeByConstructor() {
        System.out.println("def ebc");
    }

    public EmployeeByConstructor(int id) { this.id = id; }

    public EmployeeByConstructor(String name) { this.name = name; }

    public EmployeeByConstructor(int id, String name) {
        this.id = id;
        this.name = name;
    }

    void show() {
        System.out.println(id + " " + name);
    }
}

Setter를 사용하는 방법

public class EmployeeBySetter {
    private int id;
    private String name;
    private String city;

    public int getId() { return id; }

    public void setId(int id) { this.id = id; }

    public String getName() { return name; }

    public void setName(String name) { this.name = name; }

    public String getCity() { return city; }

    public void setCity(String city) { this.city = city; }

    void display() {
        System.out.println(id + " " + name + " " + city);
    }
}

테스트

public class EmployeeTest {
    public static void main(String[] args) {
        EmployeeByConstructor e = new EmployeeByConstructor(10, "gi");

        e.show(); // 10 gi

        EmployeeBySetter e2 = new EmployeeBySetter();
        e2.setId(11);
        e2.setName("gye");
        e2.setCity("Seoul");

        e2.display(); // 11 gye Seoul
    }
}

Resources

반응형