Spring

스프링 DI란?

자바지기 2022. 11. 6. 19:30
반응형

DI란?

Dependency Injection, 즉 의존 주입이다. 의존 주입에 대해서 알아보기 전에 의존에 대해서 알아보자.

 

의존이란?

A객체가 B객체의 메서드를 실행하는 경우 A객체는 B객체에게 의존한다고 표현한다.

A객체가 B객체에게 메시지를 보내는 경우라고 생각하자. 

B객체가 변경될 때 A객체도 변경된다면 A객체가 B객체에게 의존하는 것이다.

의존 주입을 해야하는 이유?

의존하는 객체를 직접 생성한다면 변경에 유연하게 대처할 수 없다. 

예시를 통해 확인해보자.

 

public class Service {
    private Dao dao = new MemberDao();
}
public class Service {
    private Dao dao = new UserDao();
}

위와 같이 Dao객체를 직접 생성한다면 Dao 객체가 변경될 때 다음과 같이 Service 클래스를 변경해야한다.

 

 

하지만 의존 주입을 사용하면 코드의 변경이 줄어든다.

public class Service {
    private final Dao dao;

    public Service(Dao dao) {
        this.dao = dao;
    }
}

위처럼 변경한다면 dao 객체가 변경되어도 Service 내부를 변경할 필요가 없다.

 

물론, Service 객체를 생성하는 곳에서는 Service에 dao를 주입해주는 코드를 변경해야한다.

Dao dao = new MemnerDao();
Service service = new Service(dao);

// 실제 객체를 생성하는 곳이 수정된다.
// dao 객체가 변경되었을 때!

Dao dao = new UserDao(); // 이 부분만 변경하면 된다.
Service service = new Service(dao);

스프링에서는 위처럼 필요한 객체를 생성하고 주입하는 기능을 제공한다. 

이것이 스프링 DI이다.

 

스프링은 어떻게 DI를 제공해주는 것일까?

예시를 통해 설정파일을 통해서 DI가 진행되는 과정을 알아보자

@Configuration
public class AppCtx {

    @Bean
    public Dao memberDao() {
        return new MemberDao();
    }

    @Bean
    public Dao userDao() {
        return new UserDao();
    }

    @Bean
    public MemberService memberService() {
        return new MemberService(memberDao());
    }

    @Bean
    public UserService userService() {
        return new UserService(memberDao());
    }
}

 

memberService()userService() 는 파라미터로 동일한 메소드인 memberDao를 호출하였다.

 

그리고 다음과 같이 main을 실행해보았다.

public class Main {
    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(AppCtx.class);
        MemberService memberService = ctx.getBean("memberService",MemberService.class);
        MemberDao memberDao = ctx.getBean("memberDao", MemberDao.class);

        System.out.println(memberService.getDao() == memberDao);
    }
}

의존 객체들을 생성하고 주입해주는 과정은

ApplicationContext ctx = new AnnotationConfigApplicationContext(AppCtx.class);

위의 코드가 실행될 때 진행되었다.

 

MemberService memberService = ctx.getBean("memberService",MemberService.class);

실행 시 디버깅을 통해 확인한 결과는 다음과 같다.

chapter2에서 보았던 singletonObjects를 확인해보았다.

 

image

 

확대해서 보면 다음과 같이 존재한다.

 

image

memberDao() 메소드를 통해 MemberDao 객체가 생성되었다. (MemberDao@2265)

 

 

image

그리고 UserService 객체 내부에, 위에서 생성되었던 MemberDao 객체(MemberDao@2265)가 주입되었다.

 

image

MemberService 객체 또한 같은 MemberDao 객체(MemberDao@2265)가 주입되었다.

 

정리

AppCtx 설정 클래스에서 미리 Bean 객체를 설정해주었으므로 스프링에서 MemberService와 UserService에 의존 주입을 진행할 수 있었다.

또한 스프링에서는 default로 Bean 객체를 싱글톤 객체로 만들기 때문에, memberDao() 메소드를 여러번 호출해도 항상 같은 객체를 반환함을 알 수 있었다.

따라서 MemberService와 UserService에 같은 memberDao 객체가 주입됨을 알 수 있다.

 

 

스프링이 DI를 제공하는 방식에는 여러가지가 있다.  위의 예시처럼 생성자를 통해 의존 객체를 주입할 수 있다.  

그리고 setter 메서드를 통해 주입하는 방법이 있다.

반응형