본문 바로가기

Framework/Spring

[Spring] 제어의 역전(IoC, Inversion of Control), 의존성 주입(DI, Dependency Injection)에 대하

728x90

Spring의 Ioc/DI은 Spring을 사용하면서 자연스럽게 접하게 되는 개념들이지만, 때로는 그 깊은 의미를 되새겨볼 필요가 있습니다. 이 두 가지 개념이야말로 Spring의 근본을 이루는 핵심정인 원리이기 때문이죠. 저 또한 2022년에 작성한 글을 전부 삭제하고, 새로운 마음으로 2024년에 new 포스팅 글을 작성하려고 해요.😊 


Ioc, 즉 제어의 역전(Inversion of Control)과 DI, 의존성 주입(Dependency Injection)은 코드의 결합도를 낮추고, 더 유연하고 테스트 가능한 애플리케이션을 만드는 데 필수적인 역할을 해요. 여기서 궁금한 점은 왜 Spinrg은 굳이 IoC와 DI를 통해 객체 관리를 하도록 했을까요? 🤔 그 이유는 간단하면서도 깊이가 있습니다. 
 
소프트웨어 개발의 복잡성은 종종 객체들 간의 관계에서 발생하는데, 이 관계를 개발자가 직접 관리하기 시작하면 코드가 복잡해지고 변화에 유연하지 않게 됩니다. 이런 상황을 방지하기 위해 Spring은 객체 생성과 생명주기 관리를 컨테이너가 대신하도록 만들었어요. 이렇게 하면 개발자는 비즈니스 로직에만 집중할 수 있고, 객체 간의 결합도를 낮춰 코드의 재사용성과 유지보수성을 높일 수 있게 되죠! 👍


 
하지만 이 과정에서 한 가지 문제가 있어요. 객체 간의 관계를 Spring이 관리하게 되면, 코드가 내부적으로 어떻게 동작하는지 파악하기 어려워질 수 있다는 점이에요. 이 때문에 많은 개발자들이 IoCDI를 단순히 "Spring이 알아서 해준다" 정도로만 생각하고 넘어가게 되는데, 이는 매우 위험한 접근이에요. IoCDI의 원리를 깊이 이해하지 못하면, 문제 발생 시 그 원인을 파악하기 어려울 뿐 아니라, 최적화가 필요한 순간에 제대로 대처하지 못할 수 있어요. 😤
 
많은 개발자들이 의존성 주입을 사용하면서, "왜 내 객체는 Null이야?", "Bean을 찾지 못한다" 등등의 오류를 확인하면서 당황을 합니다. 
가령, BeanNotFoundException 같은 오류는 의존성을 정확하게 주입하지 않았거나, Spring의 빈스코프나 라이프사이클을 제대로 이해하지 못했을 때 자주 발생하죠. 
 

Spring Application Beans Not Found Exception

I'm using the following application context file, <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/

stackoverflow.com

 
이제 DI를 이용한 코드의 예시를 보면서, 오늘 글을 마무리하려고 해요.🧑‍💻

import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;

@Service
@RequiredArgsConstructor
public class UserService {
    
    private final UserRepository userRepository;

    public User getUserById(Long id) {
        return userRepository.findById(id).orElse(null);
    }
}

 
위 코드는 UserService 클래스가 UserRepository를 의존하고 있는 전형적인 예에요. RequiredArgsConsturctor 어노테이션을 사용해서 final이나 @NonNull으로 선언된 필드만 파라미터로 받는 생성자를 자동으로 생성해 줍니다.
 

[Spring] 롬복 어노테이션(@NoArgsConstructor, @RequiredConstructor, @AllArgsConstruct)에 대해서 - 컴도리돌이

생성자 주입(Constructor Injection)은 의존성 주입의 한 종류로, 객체를 생성할 때 해당 객체가 필요로 하는 의존성을 생성자를 통해 주입하는 방식이에요. 스프링 프레임워크에서는 Autowired 어노테이

comdolidol-i.tistory.com

 
이로써 Spring 컨테이너는 UserRepository의 인스턴스를 자동으로 주입해 주죠. 이를 통해 UserServiceUserRepository에 대한 직접적인 의존성을 가지지 않게 되고, 이는 코드의 결합도를 크게 낮춰줘요. DI를 통해 객체 생성과 관리의 책임이 개발자에게서 Spring 컨테이너로 넘어가게 되는 거죠.