3. 필드주입

sen·2023년 10월 20일

스프링프레임워크

목록 보기
2/7
  • Coding, Computer이라는 두개의 클래스가 있다고 생각하자.
  • Coding은 Computer에 의존한다
  • 필드주입은 final 키워드를 사용할 수 없다.

Computer

  1. computer라는 클래스 생성 후 어노테이션을 통해 해당 객체를 스프링에서 관리하도록 지정
  2. Data 어노테이션을 등록한다.( 롬복에서 제공해주는 몇몇 메서드를 자동으로 생성해준다.)
package com.example.ex00.dependency;

import org.springframework.stereotype.Component;

import lombok.Data;

@Component //해당 객체를 Spring에서 관리하도록 설정(스프링에게 너가 좀 관리해주라)
@Data
public class Computer {

}

Coding

  1. 똑같이 스프링에서 관리하도록 Component어노테이션을 등록해주고
  2. Data어노테이션을 만들어준다. 이 어노테이션을 통해서 원래 필드주입에서는 final키워드를 사용하지 못하지만 생성자가 만들어 지면서 지금당장은 사용할 수 있게 된다.(생성자를 통해서 값을 받아서 그 값이 초기화에 들어갔기 때문에 오류가 안나는것)
  3. 아무튼 Coding 클래스 안에 의존하는 객체를 만들어주는데, 의존은 너무나 단단해서 Computer밖에 못쓰는 걸 방지하고자 의존성 주입을 하게 된다. 그래서 new 키워드로 직접 주입하는 것이 아니라 @Autowired 어노테이션을 사용한다.
  4. WebApplicationContext객체가 서버가 돌아가 실행되면서 이런 어노테이션이 붙어져있는 애들을 처리하고,
  5. Coding을 사용하기 위해서 Coding의 필드를 메모리에 올리는 순간 computer도 스프링에서 자동으로 주입된다.
⚠️ 정석으로는 필드주입에서는 final키워드를 사용할 수 없어 다른곳에서 변형이 가능하다.
package com.example.ex00.dependency;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import lombok.Data;

@Component
@Data
public class Coding {
	// 주의할 점은, 생성자랑은 별도로 주입되서, 순환참조(무한루프)시 오류가 발생하지
	//않기 때문에 StackOverFlow가 발생된다.

	@Autowired
	private final Computer computer; 

}

단위테스트를 해보자.

  • 단위테스는 WAS서버랑 다르게 JUit이라는 프로그램으로 돌린다.
  • 그래서 RunWith를 통해 어떤 프로그램인지 , xml파일 경로를 설정해야한다.
  • Log4j는 출력하는 용도의 어노테이션이다.
  • root-context에 관리하는 파일들의 패키지를 작성해줘야 @Component 어노테이션이 붙어있는 클래스들을 찾을 수 있다.
  • 고로, Namespace에 context를 클릭해주고, <context:component-scan base-package=””/>에 패키지를 입력해줘야 한다.
package com.example.ex00.dependency;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import lombok.extern.log4j.Log4j;

// 이 클래스 파일은 was랑 별도로 돌아야됨 서버가 아니라 junit 프로그램을 돌리는것

@RunWith(SpringJUnit4ClassRunner.class) //어떤 프로그램을 돌릴것인가
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml") //xml파일 경로를 적어줌으로 써  runwith가 돌아갈때 xml을 참조해서 돌아감
@Log4j
public class DependencyTests {
	
	@Autowired
	private Coding coding; 
	
	@Test
	public void checkDependencyInjection() {
		log.info("-----------------");
		log.info("coding :"+coding);
		log.info("computer :"+coding.getComputer());
		log.info("-----------------");
	}
	
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
	
	<!-- Root Context: defines shared resources visible to all other web components -->
		<context:component-scan base-package="com.example.ex00.dependency" />
</beans>

정리

  • 어떤 클래스를 만들었을 때, 외부에서 이 클래스의 필드에 접근하기 위해서 객체화 한다.
  • 유연한 개발을 위해서 의존성 주입을 Autowired를 통해서 하는데, 그렇기 위해서는 스프링이 존재에 대해서 알아야하고(@Component), root-context에 그 존재의 경로를 적어줘야한다. 그러면WebApplicationContext객체가 root-context에 들어가서 componentent들을 찾는다.

💡 final 사용하면 안되지만 **필드주입에서 final 키워드를 써도 오류가 안났던 이유**
  • final은 상수 이기 때문에, 선언과 동시에 값을 지정해줘야한다.
  • 필드 주입을 하게 되면 클래스를 메모리에 올리고 난 후에 주입을 하는 거라서 값이 없으니 오류가 난다.(필드주입으로 만 사용했을 경우에는 final 키워드를 사용할 수 없다. )
  • 하지만, @Data를 사용하면 초기화 생성자 까지도 자동으로 만들어진다.(ex) Coding(computer))
  • 생성자를 통해서 값을 받아서 그 값이 상수의 초기화때 들어가서 사용할 수 있었다.
profile
가보자고~!

0개의 댓글