record logo record

Spring Framework에서 중요한 특징 중 하나인 의존관계 주입(DI, Dependency Injection) 방법에 대해서 알아보겠습니다.

목차

DI(Dependency Injection) 란?

의존성 주입 방법에 대해서 알아보기 전에 애플리케이션의 의존관계 형태 를 알아보겠습니다.

new 연산자 활용

일반적인 애플리케이션에서 new 연산자 를 사용해서 의존 관리를 했습니다.

다음은 Main이 MemberService 객체를 new로 생성, MemberService가 MemberDAO객체를 생성하고 해당 인스턴스를 이용하는 형태와 코드입니다.

web-spring-di-use-new

Class MemberService {
    MemberDAO memberDAO = new MemberDAO();
    
    public int save(MemberVO member) {
        return memberDAO.save(member);
    }
    ...
}

DI Container 활용 : new 연산자 제거

일반적인 애플리케이션과 달리 스프링에서는 의존성 주입(DI)를 개발자가 직접(new 연산자 활용) 하지 않고 DI 컨테이너가 대신 해줍니다. 이러한 개념은 스프링에서 “인스턴스를 제어하는 주도권이 역전 되었다” 라는 의미의 IOC(Inversion of Control) 라고 합니다.

DI와 IOC에 대한 내용은 DI와 IoC를 참고해주세요.

web-spring-di-use-container-delete-new

위의 형태를 보면 new 연산자를 사용하지 않습니다.

그리고 Main이 이용하는 Service와 Service가 이용하는 DAO 인스턴스를 DI 컨테이너가 대신 생성 해주고 있음을 볼 수 있습니다. 또한, DAO 인스턴스를 Service에 의존관계 주입(DI)하고 있습니다.

개발자의 어떤 설정으로 DI 컨테이너가 각각의 인스턴스들의 의존관계를 만드는지에 대해서는 의존성 주입 방법 에서 설명하겠습니다.

DI Container 활용 : Interface

인터페이스 기반의 컴포넌트화를 하려면 MemberService와 MemberDAO를 인터페이스로 만들고 구현 클래스는 Impl을 덧붙입니다(MemberServiceImpl).

web-spring-di-use-container-interface

※참고※
인터페이스 기반 컴포넌트화 하는 이유?
소프트웨어 공학에서 결합도, 응집도라는 개념이 있습니다. 이때 결합도는 낮추고 응집도를 높여야 좋은 소프트웨어라고 합니다. 결합도를 낮추기 위한 방법으로 비즈니스 로직에 인터페이스를 두는 방법과 DI을 통해 결합도를 낮출 수 있습니다.

의존성 주입 방법

XML, Annotation, Java 기반 설정을 통해서 객체간의 의존 관계를 설정합니다.

XML

생성자 기반 의존성 주입

생성자 기반 의존성 주입방법에 대해서 알아보겠습니다.

<!-- applicationContext.xml -->
<bean id="memberDAO" class="com.test.di.persistence.MemberDAOImpl"></bean>
<bean id="memberService" class="com.test.di.service.MemberServiceImpl">
    <constructor-arg ref="memberDAO"/>
</bean>

xml 파일에 service와 dao 인스턴스들을 빈으로 등록합니다. 그리고 태그를 사용해서 service와 dao의 의존관계를 설정해 줍니다.

// MemberServiceImpl.java
public class MemberServiceImpl implements MemberService {
    
    private MemberDAO memberDAO;

    public MemberServiceImple( MemberDAO memberDAO ) {
        this.memberDAO = memberDAO;
    }
    ...(생략)
}

이렇게 xml에 의존성 주입을 설정이 끝나면 MemberServiceImpl.java 에서 생성자로 dao와의 의존관계를 주입해줍니다.

설정자(Setter) 기반 의존성 주입

설정자(Setter) 기반 의존성 주입 방법을 알아보겠습니다.

<!-- applicationContext.xml -->
<bean id="memberDAO" class="com.test.di.persistence.MemberDAOImpl"></bean>
<bean id="memberService" class="com.test.di.service.MemberServiceImpl">
    <property name = "memberDAO" ref="memberDAO" />
</bean>

생성자 방식과 다르게 태그가 아닌 태그를 사용해서 의존관계를 설정해 줍니다.

// MemberServiceImpl.java
public class MemberServiceImpl implements MemberService {
    
    private MemberDAO memberDAO;

    public setMemberDAO( MemberDAO memberDAO ) {
        this.memberDAO = memberDAO;
    }
    ...(생략)
}

MemberServiceImpl.java 에는 생성자가 아닌 setXXX()로 의존관계를 주입해줍니다.

Annotation

@Autowired로 의존성 주입하기

먼저 @Autowired와 xml에 설정으로 의존성 주입하는 방법을 알아보겠습니다.

<!-- applicationContext.xml -->
<bean id="memberDAO" class="com.test.di.persistence.MemberDAOImpl"></bean>
<bean id="memberService" class="com.test.di.service.MemberServiceImpl"></bean>
<context:annotation-config /> 

xml에는 service와 dao의 빈들을 등록 해 줍니다. 그리고 태그를 등록해줍니다.

// MemberServiceImpl.java
...
import org.springframework.beans.factory.annotation.Autowired;

public class MemberServiceImpl implements MemberService {
    
    @Autowired // 의존관계 주입
    private MemberDAO memberDAO;
    
    ...(생략)

xml설정이 끝났다면 빈과 다른 빈과의 의존성을 자동으로 연결해주는 @Autowired를 사용하면 의존관계가 설정이 완료 됩니다.

@Component와 @Autowired로 의존성 주입

다음은 @Component와 @Autowired로 의존성 주입하는 방법을 알아보겠습니다.

<!-- applicationContext.xml -->
<context:component-scan base-package="com.test.di.persistence"></context:component-scan>
<context:component-scan base-package="com.test.di.service"></context:component-scan>

xml에 위와 같이 태그를 입력해 줍니다.

// MemberDAOImpl.java
@Component // 빈 등록
public class MemberDAOImpl implements MemberDAO {
    ...
}

// MemberDAOImpl.java
@Component // 빈 등록
public class MemberServiceImpl implements MemberService {

    @Autowired // 의존관계 주입
    private MemberDAO memberDAO;
    
    ...
}

그리고 위와 같이 빈으로 등록할 클래스들을 @Component을 선언해 줍니다. 이렇게 되면은 xml에 설정한 의 base-package를 검색해서 @Component가 설정된 클래스들을 찾아서 빈으로 등록하게됩니다.

그리고 @Autowired를 사용하여 의존관계를 주입하게 됩니다.

Java

Java를 이용한 의존성 주입 설정은 XML 문법 대신 자바 코드로 빈을 설정 합니다.

// JavaConfig.java
@Configuration
public class JavaConfig {
    @Bean
    public MemberDAO memberDAO() {
        return new MemberDAOImpl();
    }

    @Bean(name="service")
    public MemberService memberService() {
        return new MemberServiceImpl(memberDAO());
    }
}

위와 같이 Java를 이용하여 의존성 주입 설정을 할 수 있습니다.

public class Main {

    private static ApplicationContext ctx = null;

    public static void main(String[] args) throws Exception {
        ctx = new AnnotationConfigApplicationContext(JavaConfig.class); // 자바설정 클래스
        MemberService memberService = ctx.getBean("service", MemberService.class); // 가져올 빈 이름
    }
}

그리고 위와 같이 Main 클래스에서 해당 JavaConfig클래스를 사용할 수 있습니다.

References