DEV&OPS/Java

Spring 의존성 주입과 제어의 역전

ALEPH.GEM 2025. 11. 4. 21:02

인터페이스를 이용한 느슨한 결합의 필요성

애플리케이션이 프로젝트 도중 설계가 바뀌거나 유지 보수 중에 클래스에 변경이 이루어 지는 경우는 흔하게 발생합니다.

그런 상황에 대응하기 위해 스프링에서는 인터페이스를 이용해 클래스간 느슨한 결합을 하도록해서 의존  관계에 있는 클래스들이 도중에 바뀌더라도 인터페이스가 바뀌지 않는 이상 다른 클래스에 없도록 하는 것입니다.

 

 

의존성 주입(Dependency Injection)

의존성 주입은 디자인 패턴으로 제어의 역전(Inversion of Control)을 구현하기 위한 방법중의 하나입니다.

객체를 직접 생성하는 것이 아닌 외부에서 생성하여 주입 받는 방법을 말합니다.

예를 들어 컨트롤러들은 서비스 객체들을 가져다 주입 받아 사용하는데, 이런 컨트롤러들은 서비스 객체에 의존적이라고 합니다.

이처럼 클래스들은 서로 연결되어 있어서 의존성(dependency)이 강합니다.

그래서 인터페이스를 통해 클래스 사이의 직접적인 의존성을 제거해서 서로 느슨하게 결합하도록 유도하는 것입니다.

그래서 요구사항이 변경되어 클래스를 수정하게 될 때 의존하고 있던 클래스에 영향을 끼치지 않으면서 클래스를 수정할 수 있게 해주는 것입니다.

IoC 컨테이너는 시스템의 모든 인스턴스 객체를 관리하고 인스턴스 객체들 사이의 의존성이 있으면 주입하는 일을 담당합니다.

Spring에서는 XML 설정이나 자바 클래스내 Config 설정등 다향한 방법을 이용해 필요한 객체들을 찾아서 사용할 수 있도록 이를 구현하고 있습니다.

 

 

일반적인 자바 객체의 생성과 초기화

public class Service{
    private final Persistence persistence;
    
    public Service(){
    	this.persistence = new Persistence();
    }
}
public static void main(String[] args){
    Service service = new Service();
}

외부 클래스의 생성자를 호출하여 객체를 생성하여 초기화하는 일반적인 방법입니다.

이 경우 Persistence 클래스에 의존(dependent)하고 있어서 Persistence 클래스가 없다면 제 기능을 하지 못합니다.

Service클래스는 Persistence클래스에 의존하고 있으며, Service클래스가 Persistence 객체를 생성하고 관리합니다.

 

 

Setter를 이용한 의존성 주입 예제

public class Service{
    private final IPersistence persistence;
    
    public void setIPersistence(IPersistence persistence){
        this.persistence = persistence;
    }
}
public static void main(String[] args){
    IPersistence persistence = new Persistence();
    Service service = new Service();
    service.setIPersistence(persistence);
}

일반 적인 방법과 의존성 주입의 차이점은 인터페이스를 이용한다는 점과 객체를 외부에서 생성해서 setter(혹은 생성자)로 객체를 전달(주입)한다는 점입니다.

이러한 의존성 주입을 관리해주는 컨테이너 중 하나가 바로 스프링(Spring) 프레임워크입니다.

 

생성자 주입 방식

Spring3 이후 부터는 생성자 주입 방식으로 의존성 주입을 더 많이 활용합니다.

생성자 주입 방식의 규칙

1. 주입받아야 하는 객체의 변수는 final로 작성합니다.

2. 생성자를 이용해서 해당 병수를 생성자의 파라미터로 지정합니다.

 

이 생성자 주입 방식은 객체를 생성할 때 문제가 발생하는지 미리 확인할 수 있기 때문에 Setter를 이용한 주입 방식 보다 선호됩니다.

Lombok 라이브러리를 사용하면 @RequiredArgsConstructor 라는 어노테이션을 이용해서 생성자를 자동으로 작성 할수 있게 해주기 때문에 편리합니다.

import lombok.RequiredArgsConstructor;
import lombok.ToString;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
@ToString
@RequiredArgsConstructor	//생성자 주입 방식 
public class SampleService {
    @Autowired
    private final SampleDAO sampleDAO;  //주입 받아야 하는 변수를 final으로
}

 

 

스프링 프레임워크(Spring framework)

프로젝트의 규모가 커질수록 관리해야 하는 객체들이 많아질 수록 의존성 주입 컨테이너를 통해 객체의 생성과 관리하는 방법이 효율적이게 됩니다.

public class MyService{
    Service service;
    ShareService shareService;
    NotiService notiService;
    ScheduledService scheduledService;
}

public class ShereService{
    UserService userService;
    EventService eventService;
    SharePersistence persistence;
}

public class NotiService{
    EventService eventService;
    UserService userService;
    NotiPersistence persistence;
}

public class SharePersistence{
    JDBCConnection connection;
    ...
}
JDBCConnection connection = new JDBCConnection();
Service service = new Service();
UserService userService = new UserService();
EventService eventService = new EventService();
NotiPersistence notiPersistence = new NotiPersistence(connection);
SharePersistence sharePersistence = new SharePersistence(connection);
ShareService shareService = new ShareService(userService, eventService, sharePersistence);
NotiServie notiService = new NotiService(userService, eventSerivce, sharePersistence);
MyService myService = new MyService(Service, shareService, notiService, new ScheduledService());

이렇게 의존하는 객체들이 많아질 수록 객체 관리가 어려워지게 되는데 Spring의 어노테이션, xml, class 를 이용해서 bean객체간의 의존성을 명시할 수 있습니다.

어플리케이션(WAS) 시작시 spring Ioc컨테이너가 객체를 생성해주고 관리도 해주게 됩니다.

위 예제를 Spring 어노테이션을 이용해서 아래 예제처럼 의존성을 명시할 수 있습니다.

@Service
public class MyService{
    @Autowired Service service;
    @Autowired ShareService shareService;
    @Autowired NotiService notiService;
    @Autowired ScheduledService scheduledService;
}

@Service
public class ShareService{
    @Autowired UserService userService;
    @Autowired EventService eventService;
    @Autowired SharePersistence persistence;
}

@Service
public clasee NotiService{
    @Autowired EventService eventService;
    @Autowired UserService userService;
    @Autowired NotiPersistence persistence;
}

@Service
public class SharePersistence{
    @Autowired JDBCConnection connection;
    ...
}

위 예제 처럼 의존관계를 명시해주면 일일이 new 해서 객체를 생성하는 작업을 하지 않아도 됩니다.

이러한 작업을 ApplicationContext 객체가 대신 해주게 됩니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90