관리 메뉴

Just Do it

Spring DI 활용하기: 이론 본문

신입 개발자가 되기 위해 공부했던 독학 자료들/Spring

Spring DI 활용하기: 이론

Seojoo21 2022. 2. 14. 11:38

 

1. 빈(bean)이란?

- JavaBeans: 재사용 가능한 컴포넌트, 상태(iv), getter&setter, no-args constructor

- Servlet & JSP bean: MVC의 Model, EL, scope, JSP container가 자바 객체를 관리

- EJB: 복잡한 규칙, EJB container 가 관리

- Spring Bean: POJO (Plain Old Java Object), 단순, 독립적, Spring container가 관리

 

2. BeanFactory와 ApplicationContext

- Bean: Spring Container가 관리하는 객체

- xml 문서에 <bean> 태그를 여러개 쓰는 것을 '빈 정의'라고 하는데 이걸 Spring Container가 읽어들여서 빈에 정의된 클래스 객체를 만들어낸다.

- Map 에 Key, Value로 각각 빈의 이름, 빈 객체의 주소를 가지고 있다.

- Spring container: Bean 저장소, Bean을 저장, 관리(생성, 소멸, 연결)한다.

* 빈의 Life Cycle(생성, 소멸) 뿐만 아니라 객체들의 관계까지 연결해준다. 예) @Autowired 

- BeanFactory: Bean 생성, 연결 등의 기본 기능을 정의

- ApplicationContext: BeanFactory를 확장해서 여러 기능을 추가 정의한 것. 스프링으로 애플리케이션을 개발할 때 우리가 작성한 프로젝트 전체 모듈을 관리하는 것이 ApplicationContext이다. 

- Spring Container와 ApplicatonContext는 거의 같은 말이다. 

 

3. ApplicationContext의 종류 

- BeanFactory처럼 ApplicationContext도 interface이다. 

- 다양한 종류의 ApplicationContext 구현체를 제공한다.

- 설정을 XML로 하느냐, Java Config로 하느냐에 따라 다르다.

AC의 종류 XML: <bean> 태그 Java Config: @Bean 애노테이션
non-Web GenericXmlApplicationContext AnnotationConfigApplicationContext
Web XmlWebApplicationContext AnnotationConfigWebApplicationContext

 

4. Root AC와 Servlet AC

- Root AC와 Servlet AC가 초기화가 시작되고 초기화가 잘 끝났는지 보는게 중요. 

- 실행이 잘 안되면 로그를 보고 각 AC들이 잘 초기화가 끝났는지 봐야 한다. 그럼 root-context.xml 설정이 잘못되었는지, servlet-context.xml 설정이 잘못되었는지 확인할 수 있다.  

 

5. ApplicationContext의 주요 메서드

타입 메서드 설명
Object getBean() 빈 얻기 
boolean isPrototype / isSingleton() 빈이 프로토타입인지 싱글톤인지 확인 
boolean isTypeMatch() 빈의 타입 확인 
int getBeanDefinition() 정의된 빈의 갯수 

 

6. IoC(Inversion of (flow) Control) 와 DI (Dependency Injection) 

- IoC: 실행 흐름을 전통적인 방식과 다르게 뒤바꾸는 것. 

- IoC(Inversion of Control) inverts the flow of control as compared to traditional control flow.

* 전통적인 방식: 사용자 코드가 Framework 코드를 호출. 호출을 하고 결과를 받는 것. 

// [전통적인 방식] 사용자 코드가 Framework 코드를 호출

Car car = new Car();
car.turboDrive();

void turboDrive() {
	engine = new TurboEngine();
    engine.start();
    ...
}

- IoC: Framework 코드가 사용자 코드를 호출.

* 의존성 주입 DI: 사용할 객체를 외부에서 주입받는 것. Framework이 사용할 코드를 우리가 준다. 

* DI(Dependency Injection): the passing of a dependency into the client that uses it.

* 수동 주입: new ()로 직접 클래스를 지정하는 것

* 자동 주입: @Autowired 어노테이션 사용 

 

//[IoC] Framework 코드가 사용자 코드를 호출 
Car car = new Car();
car.drive(new SuperEngine()); // 수동으로 DI 주입. 자동으로 주입하려면 아래 void drive 메서드 앞에 @Autowired를 붙여주면 된다. 

void drive(Engine engine) {
	engine.start();
    ...
}

 

6.1 스프링 애너테이션: @Autowired

- 스프링 내부에서 자신이 특정한 객체에 의존적이므로 자신에게 해당 타입의 빈을 주입해주라는 표시 

- 인스턴스 변수(iv), setter, 참조형 매개변수를 가진 생성자, 메서드에 적용. 

- Spring Container에서 타입으로 빈을 검색해서 참조 변수에 자동으로 주입해준다. (DI) 

- 검색된 빈이 n개이면, 그 중에 참조변수와 이름이 일치하는 것을 주입. 

- 주입 대상이 변수일 때, 검색된 빈이 1개 아니면 예외 발생 (반드시 1개여야 함) 

- 주입 대상이 배열일 때, 검색된 빈이 n개라도 예외 발생하지 않음 (n개여도 괜찮음) 

*그러나 @Autowired(required=false)이면 검색된 빈이 0개여도 괜찮음 

- 생성자에는 @Autowired 생략 가능. 그러나 기본 생성자를 포함하여 생성자가 여러개 있을 때 @Autowired 를 생략하면 안된다. (왜냐하면 생성자가 2개기 때문에) 

 

6.2 스프링 애너테이션: @Resource (or @Resource(name=" ")) 

- Spring Container에서 이름으로 빈을 검색해서 참조 변수에 자동으로 주입해준다. (DI) 

- 일치하는 이름의 빈이 없으면, 예외 발생 

- @Resource 뒤에 (naml= ""), 즉 이름을 생략하면, 참조변수의 이름이 빈의 이름으로 들어간다. (이름 생략 가능) 

 

class Car {
	// @Resource(name="engine") // 아래와 같다. 
	@Resource
    Engine engine 
}
class Car {
	@Autowired // 1. 타입으로 검색한 다음 
    @Qualifier("superEngine") // 2. 같은 타입의 빈이 여러개 있으면 @Qualifier로 어떤 빈을 주입할지 결정
    Engine engine;
}


class Car {
	@Resource(name="superEngine") // 이름이 superEngine인 빈을 찾아 주입 
    Engine engine;
}

 

 

6.3 스프링 애너테이션: @Component 

- 해당 클래스가 스프링에서 객체로 만들어서 관리하는 대상임을 명시하는 애너테이션 

- <component-scan> 태그로 @Component 클래스를 자동 검색해서 빈으로 등록

- @Controller, @Service, @Repository, @ControllerAdvice의 메타 애너테이션  

<context:component-scan base-package="com.fastcampus.ch3">
	<context:exclude-filter type="regex" expression="com.fastcampus.ch3.diCopy*.*" />
</context:component-scan>
@Component("superEngine") // 아래와 동일 
@Component // 이름을 지정해주지 않으면 클래스 이름의 첫글자 대문자만 소문자로 바꾼 것을 이름으로 쓰기 때문에 위와 동일하다 
class SuperEngine extends Engine {}

 

6.4 스프링 애너테이션: @Value와 @PropertySource

- 값을 지정할 때 사용

- SystemProperties 값이나 SystemEnvironment 값을 가져와 주입할 수 있다. 

class Car{
	
	@Value("red") String color; // 인스턴스 변수 color에 "red"라는 값 부여
	@Value("100") int oil;      // 인스턴스 변수 oil에 100이라는 값 부여 (int여도 큰따옴표 안에 써야함) 
	@Autowired Engine engine; // byType - 타입으로 먼저 검색 후 여러개인 경우 이름으로 찾는다 
	@Autowired Door[] doors;
    ...
    
}


@Component
@PropertySource("setting.properties") 
// setting.properties라는 파일을 작성하여 src/main/resources 폴더 안에 넣어두면
// 그 파일에서 @Value 어노테이션과 EL을 이용하여 값을 읽어올 수 있다.
class SysInfo {
	@Value("#{systemProperties['user.timezone']}")
	String timeZone;
	@Value("#{systemEnvironment['SHELL']}")
	String currentDir;
	@Value("${autosaveDir}")
	String autosaveDir;
	@Value("${autosaveInterval}")
	int autosaveInterval;
	@Value("${autosave}")
	boolean autosave;
	
	@Override
	public String toString() {
		return "SysInfo [timeZone=" + timeZone + ", currentDir=" + currentDir + ", autosaveDir=" + autosaveDir
				+ ", autosaveInterval=" + autosaveInterval + ", autosave=" + autosave + "]";
	}

 

 

6. 스프링 애너테이션 vs 표준 애너테이션 (JSR-330, 자바에서 제공) 

- javax.inject-1.jar : @inject, @Named, @Qualifier, @Scope (스프링의 @Scope와 다름), @Singleton

- annotations.api.jar : @Resource, @ManagedBean, @PreDestroy, @PostContruct

스프링 애너테이션 표준 애너테이션   비고 
@Autowired @Inject   @Inject에는 required 속성이 없다. 
@Qualifier @Qualifer, @Name   스프링의 @Qualifer는 @Named와 유사
  @Resource   스프링에는 이름 검색이 없다. 
@Scope("singleton") @Singleton   표준에서는 prototype이 디폴트 
@Component @Named, @ManagedBean   표준에서는 반드시 이름이 있어야 함 

 

6. 빈의 초기화: <property> 와 setter

- <property> 를 이용한 빈 초기화. setter를 이용 

- 메서드 내 setter를 사용하는 대신, servlet-context.xml 파일에 <property> 태그를 추가하여 빈을 초기화 할 수 있다.  

 

6. 빈의 초기화: <constructor-arg>와 생성자 

- <constructor-arg>를 이용한 빈 초기화. 생성자를 이용

- 메서드 내 생성자를 사용하는 대신, servlet-context.xml 파일에 <constructor-arg> 태그를 추가하여 빈을 초기화할 수 있다.