WEB/Spring

[Spring]DI와 Autowired 확실히 알고 사용하기

MoonSta 2023. 1. 31. 13:11

📌Autowired 확실히 알고 사용하기

 Spring으로 개발을 하면서 수도 없이 작성하는 어노테이션 중 하나인 @Autowired이 있다. 사실 정확한 동작 원리를 알고 쓴다기보단 습관처럼 선언하고 사용했기에 이번 포스팅을 통해 정확히 정리하고 넘어가려고 한다. 우선 Spring Framework의 큰 특징인 DI(Dependency Injection)에 대해 간단하게 알아보자.

 

 

📌DI(Dependency Injection)

 DI(Dependency Injection)은 다른 Framework에서는 볼 수 없는 Spring에서 제공하는 의존 관계 주입 기능을 말한다. 즉, 필요할 때마다 객체를 생성해서 사용하는 것이 아닌 미리 생성 후 필요한 부분에 주입하여 사용할 수 있다. 이러한 기능을 사용하면 결과적으로 객체 간의 결합을 낮추고, 유지보수의 용이함을 가져온다. 이제 이러한 개념을 바탕으로 @Autowired를 자세히 알아보자.

 

 

📌@Autowired

@Autowired
private TestDAO testDAO;

 Spring Framework를 기반으로 생성된 프로젝트를 보면 위와 같은 형식으로 @Autowired가 사용된다.  도대체 @Autowired 어노테이션은 무슨 용도로 사용하는 것일까? 이 질문에 대한 답을 DI(Dependency Injection)과 연관 지어 생각해 보자. 

 

 Spring Framework에서의 DI(Dependency Injection)은 객체 내에서 또 다른 객체가 필요로 할 때 사용을 해야 되고 직접 Bean을 등록하는 등 직접 주입을 해주어야 했습니다. 이러한 방법을 간결하게 해 주기 위해 @Autowired 어노테이션이 등장하였습니다. 즉,  @Autowired는 Spring Container에 등록된 Bean 중 타입이 일치하는 객체를 어노테이션 한 번으로 주입시켜 주는 어노테이션이다. 이러한 주입은 세 가지의 방법으로 사용할 수 있다.

 

 

💉필드 주입 - (Field Injection)

@Autowired를 필드 내에 직접 주입

public class TestController {
    @Autowired
    private TestService testService;
}

 

 하지만, 이 방식은 실제 개발에서 몇 가지 이유로 권장되지 않는 방법이다. 그 이유는 다음과 같다. 첫 번째로 필드 주입을 하게 되면 외부에서 접근이 불가능하다. 따라서 테스트 시 객체의 수정이 불가능하기 때문에 사용을 지양한다. 두 번째로 순환 참조를 하게 되는 문제가 발생한다. 코드를 예로 들자

 

//A클래스 - B클래스 주입
public class A {
    @Autowiredd
    private B b;
    
    public void Amethod() {
        B.Bmethod();
    }
}
//B클래스 - A클래스 주입
public class B {
    @Autowiredd
    private A a;
    
    public void Bmethod() {
        A.Amethod();
    }
}


//테스트
public class test {
    @Autowired
    private A a;
    
    @Autowired
    private B b;
    
    public void tetsMethod() {
        A.Amethod();
        B.Bmethod();
    }  
}

 

 위의 코드에서 클래스 A와 클래스 B는 서로를 주입받았다. 이러한 상황에서 Test 클래스의 testMethod()가 실행을 하게 되면 서로를 계속 참조하여 서버가 다운되는 상황이 발생합니다. 이러한 이유로 필드 주입을 지양하게 되었습니다.

 

 

💉수정자 주입 - (Setter Injection)

수정자를 통해 의존성을 주입 - 수정 가능성이 있는 의존관계에 사용

 

private TestDAO testDAO;

@Autowired 
public void setTestDao(TestDAO testDAO) {
    this.testDAO = testDAO;
}

 

 사실 이 수정자 주입 방식도 문제가 있다. Setter 자체가 public 메서드이기 때문에 주입받는 객체의 변경이 될 수 있기 때문이다. 따라서 Spring에서는 이다음에 나올 생성자 주입(Constructor Injection)의 사용을 강력하게 권장한다.

 

 

💉생성자 주입 - (Constructor Injection)

생성자 주입의 특징은 필수적인 의존관계에 사용된다.

 

@RestController
public class TestController {
    
    private TestService testService;
    
    @Autowired
    public TestController(TestService testService) {
        this.testService = testService;
    }
}

 

 생성자 주입 외에 필드 주입이나 수정자 주입에서는 여러 가지 문제가 생겼습니다. 또한 인텔리제이와 같은 특정 툴에서는 필드 주입 시 경고 메시지를 띄워줍니다. 생성자 주입(Constructor Injection)을 하게 되면 다른 주입방식의 단점들을 보완할 수 있고 final 키워드를 사용함으로써 잘못 주입되는 경우도 예방 가능합니다. 무엇보다 테스트 코드를 작성하는데 용이합니다. 따라서 이러한 이유들로 인해 생성자 주입 방식은 Spring에서 가장 권장하는 방식입니다.