본문 바로가기
Study/Spring

[Spring] 2. DI(Dependancy Injection)란?

by 나아가는 2023. 9. 24.
반응형

DI 는 의존을 처리하는 방식이다.

의존에 대한 설계 패턴으로, 의존성 주입이라는 단어로 번역되어 사용된다.

스프링은 기본적으로 DI를 기반으로 동작하기 때문에, 스프링을 잘 이해하려면 DI에 대한 이해가 필수이다.

public class A {
    private B b = new B();
}

// 위의 코드보다 느슨한 의존성을 가짐
// 필요할 때만 b를 넣어서 사용 가능.
public class A {
    private B b;
    
    public A(B b) {
        this.b = b;
    }
}

위 의 코드의 경우 A클래스가 B클래스에 의존한다 라고 표현한다.

이렇게 두 클래스 간에 의존성이 있다면 몇 가지 단점이 있다.

  1. B 클래스를 상속 받은 하위 클래스 C로 변경하려고 할 때 A 클래스의 코드를 수정해 주어야 한다. B 클래스를 사용하는 클래스가 많을 수록, 수정해야 하는 코드의 양이 많아진다.
  2. 개발 단계에서 B 클래스가 완성되지 않았을 경우, A 클래스를 테스트 할 수 없게 된다.

이처럼 의존하는 객체를 직접 생산하는 방식은 개발 효율을 낮추고, 개발 생산성이 전반적으로 낮아지는 상황이 발생한다.

이러한 단점은 코드를 아래와 같은 구조로 변경하였을 때 해결 가능하다.

// 위의 코드보다 느슨한 의존성을 가짐
// 필요할 때만 b를 넣어서 사용 가능.
public class A {
    private B b;
    
    public A(B b) 
        this.b = b;
    }
}

이와 같이 A 클래스 내부에서 B객체를 직접 생성하지 않고 누군가가 의존하는 객체(의존성)를 외부에서 넣어준다(주입)는 의미로 DI라고 부른다. (= 객체를 연결(wire)한다는 표현을 쓰기도 한다.)

  1. B 클래스를 상속 받은 하위 객체로 변경하고 싶을 때 변경되어야 하는 부분은 객체를 생성하고 연결해주는 조립기로 제한된다. 객체를 필요로 하는 코드는 변경되지 않는다. (= 스프링이 이 조립기에 해당)
  2. B 클래스의 구현이 완성되어 있지 않더라도 테스트를 할 수 있다. A 클래스를 테스트 할 때 B클래스의 가짜 객체를 생성해서 테스트가 가능하기 때문에 A 클래스와 B 클래스를 동시에 구현 할 수 있다. ⇒ 개발 효율을 향상시킬 수 있다.
간단하게 가짜 구현 객체를 만들어 주는 다양한 테스트 프레임워크가 있다.
ex) Mockito 등

 

예제 ) Bean 을 이용한 DI구현

@Component, @RestController 어노테이션이 클래스에 붙어있으면 bean 에 저장되어 있다.

@Component 의 target 범위가 type이고, @Bean target 범위가 메소드 이기 때문에 @Bean 은 클래스에 사용하지 못한다.

  • new 로 객체를 생성해서 사용하지 않고 getBean으로 저장된 객체를 불러와서 사용한다. (DI)
  • Bean  scope 가 싱글톤으로 객체를 하나만 생성해서 저장하고 계속 불러와서 사용하기 때문에 여러번 호출해도 같은 주소 값을 가진다.
  • scope 옵션을 Prototype으로 변경하여 호출할때마다 객체 생성하도록 변경 가능하다.

 

config/ApplicationContextProvider.java

package kr.re.kitri.security.web.edu.config;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class ApplicationContextProvider implements ApplicationContextAware {
    private static ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public static ApplicationContext getApplicationContext(){
        return applicationContext;
    }
}

model/TestBean.java

package kr.re.kitri.security.web.edu.model;

import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class TestBean {
    String test1;

    public TestBean() {
    }

    public TestBean(String test1) {
        this.test1 = test1;
    }

    public String getHello() {
        return "hello";
    }

}

EduApplication.java > ApplicationContext 를 이용하여 getBean를 이용해 Bean 가져오기

package kr.re.kitri.security.web.edu;

import kr.re.kitri.security.web.edu.config.ApplicationContextProvider;
import kr.re.kitri.security.web.edu.model.TestBean;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@SpringBootApplication
public class EduApplication {

    public static void main(String[] args) {
        SpringApplication.run(EduApplication.class, args);
        ApplicationContext ac = ApplicationContextProvider.getApplicationContext();
				TestBean testBean2 = ac.getBean("testBean1", TestBean.class);
        TestBean testBean = ac.getBean("testbe", TestBean.class);
        TestBean testBeanTest = ac.getBean("testbe", TestBean.class);

				// 같은 객체이기 때문에 같은 주소값을 가진다.
        System.out.println("testBean의 객체값:" + testBean);
        System.out.println("testBeanTest의 객체값:" + testBeanTest); 

        System.out.println("testBean의 객체값 hello:" + testBean != null ? testBean.getHello() : "null");
    }
}

@Configuration
class AppConfig {
		// 디폴트는 싱글톤 패턴이고 변경하고 싶을 때는 
		// @Scrope() 어노테이션으로 변경 가능하다. 
    @Bean()
    public TestBean testBean1() {
        return new TestBean();
    }

    @Bean()
    public TestBean testBean2() {
        return new TestBean("hello");
    }
}

intellij에서 View>Tool Window>Spring 에 들어가면 Beans 에서 testBean이 저장되어 있는 것을 확인할 수 있다.

반응형

'Study > Spring' 카테고리의 다른 글

springboot 에서 어노테이션기반 MyBatis 적용하기 (xml 사용하지 않고)  (0) 2023.12.16
[Spring]Builder  (0) 2023.10.06
[Spring] AOP 예제  (0) 2023.09.25
[Spring] 3. AOP  (0) 2023.09.24
[Spring] Spring 시작하기  (0) 2023.09.24