[Spring] 스프링 DI 설정 방식 (생성자, 세터 방식)
2023. 7. 28.
반응형

 

https://coding-log.tistory.com/268

 

[Spring] 스프링 DI란? (Dependency Injection, 의존성 주입) (feat. 객체 조립기)

Spring에는 흔히 말하는 특징 삼대장이 있습니다. DI, AOP, IoC가 바로 그것입니다. 이번 포스팅에서는 DI, 즉 의존 주입에 대해서 다룹니다. 의존이라는 게 도대체 무슨 소리일까요? 여기에서 말하는

coding-log.tistory.com

 

이전 포스팅에서는 DI, 즉 의존과 의존성에 대한 개념을 공부했습니다. 

 

이 포스팅에서는 스프링을 이용한 DI 설정에 대해서 다루겠습니다.

 

앞의 포스팅에서 다룬 Assembler 대신 스프링을 사용하기 위해서는 약간의 설정이 필요합니다.

스프링이 어떤 객체를 생성하고, 의존을 어떻게 주입할지 설정 정보가 필요하기 때문입니다.

설정 정보를 담은 코드를 보겠습니다.

 

 

반응형

 

 

@Configuration
public class AppCtx {

	//스프링 빈 등록
	@Bean
	public MemberDao memberDao() {
		return new MemberDao();
	}
	
	//생성자 통해 주입
	@Bean
	public MemberRegisterService memberRegSvc() {
		return new MemberRegisterService(memberDao());
	}
	
	//세터(Setter)를 통해 주입
	@Bean
	public ChangePasswordService changePwdSvc() {
		ChangePasswordService pwdSvc = new ChangePasswordService();
		pwdSvc.setMemberDao(memberDao());
		return pwdSvc;
	}
	
	@Bean
	public MemberPrinter memberPrinter() {
		return new MemberPrinter();
	}
	
	@Bean
	public MemberListPrinter listPrinter() {
		return new MemberListPrinter(memberDao(), memberPrinter());
	}
	
	@Bean
	public MemberInfoPrinter infoPrinter() {
		MemberInfoPrinter infoPrinter = new MemberInfoPrinter();
		infoPrinter.setMemberDao(memberDao());
		infoPrinter.setPrinter(memberPrinter());
		return infoPrinter;
	}
	
	@Bean
	public VersionPrinter versionPrinter() {
		VersionPrinter versionPrinter = new VersionPrinter();
		versionPrinter.setMajorVersion(5);
		versionPrinter.setMinorVersion(0);
		return versionPrinter;
	}
}

 

https://coding-log.tistory.com/260

 

[Spring] 스프링 Web MVC 프로젝트 시작하기 (feat. maven, gradle의 차이)

이 포스팅은 Spring 프로젝트 생성과 파일구조에 대해 다룹니다. 그에 앞서 maven, gradle이 도대체 무엇일까요? maven과 gradle은 자바 프로젝트를 빌드할 수 있는 도구입니다. 그렇다면 이들은 무슨 차

coding-log.tistory.com

위의 포스팅에서 다뤘던 어노테이션이 또 등장했습니다.

 

@Configuration: Bean을 수동으로 등록할 때 클래스에 붙여주는 어노테이션. @Bean어노테이션이 붙어있는 메소드를 Bean으로 등록해 주며 싱글톤이 되도록 보장해 줍니다.
@Bean: 수동으로 Spring 컨테이너에 Bean을 등록하는 어노테이션.

 

라고 설명했었죠.

 

즉, @Configuration 을 붙이면 스프링 설정 클래스로 사용 가능해지고, @Bean을 붙이면 그 메소드가 생성한 객체를 스프링 빈이라고 설정하는 것입니다.

 

@Bean은 각각의 메소드마다 한 개의 빈 객체를 생성하고, 메소드 이름을 빈(Not empty) 객체의 이름으로 사용합니다.

 

ex) 

 

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

 

이 경우에는 memberDao라는 이름으로 등록되는 것입니다.

그럼 이 등록된 빈을 실제로 어떻게 사용할까요?

저번 포스팅에서 DI를 지원하는 방법이 Setter, Constructor Injection, Autowiring(자동주입) 등이 있다고 언급하고 넘어갔었습니다.

 

 

반응형

 

 

위의 코드에서는 주석에 적어놨듯이 생성자(Constructor)와 세터(Setter)를 활용한 방법으로 의존성을 주입해주고 있습니다. 이렇게 빈을 만들고 의존성을 주입하고 나면 위의 포스팅에서 다뤘던 AnnotationConfigApplicationContext, getBean을 사용해 빈을 가져와 사용할 수 있습니다.

 

 

AnnotationConfigApplicationContext: 자바 어노테이션을 이용한 클래스로부터 객체 설정 정보를 가져옴
getBean: Test.class에서 "test"라는 이름의 빈을 가져옴

 

ex)

 

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppContext.class);
MemberRegisterService regSvc = ctx.getBean("memberRegSvg", MemberRegisterService.class);

 

위의 설정을 따라서 빈을 가져오는 코드를 작성해 봤습니다.

 

AnnotationConfigApplicationContext을 사용해서 스프링 컨테이너를 생성합니다.

스프링 컨테이너가 @Configuration이 달린 클래스에서 설정 정보를 찾아 생성할 객체와 의존 주입 대상을 정합니다.

메소드의 이름이 memberRegSvg였기 때문에 빈의 이름이 memberRegSvg가 되었습니다.

memberRegSvg에서 생성자로 의존성을 주입했기 때문에 객체 내부에서 memberDao 빈 객체를 사용해 빈을 반환해 줍니다.

 

그럼 이렇게 스프링으로 DI를 하기 위한 준비를 마쳤으니 본격적으로 DI 방식에 대해 알아보도록 하겠습니다.

 

 

반응형

 

 

1. 생성자 방식

 

 

public class MemberRegisterService {

  private MemberDao memberDao;

  public MemberRegisterService(MemberDao memberDao) {
  	this.memberDao = memberDao;
  }

  public void memberRegist(Member member) {
  	memberDao.insert(member);
  }
}

@Configuration
public class AppCtx {

	//스프링 빈 등록
	@Bean
	public MemberDao memberDao() {
		return new MemberDao();
	}
	
	//생성자 통해 주입
	@Bean
	public MemberRegisterService memberRegSvc() {
		return new MemberRegisterService(memberDao());
	}
 }

 

위의 MemberRegisterService 클래스를 보면 MemberRegisterService를 객체로 사용하기 위해서는 MemberDao 객체를 주입받아 사용해야 했습니다.

이를 AppCtx 클래스에서 빈 등록, 후에 생성자를 사용해 의존성을 주입했습니다.

 

2. 세터 메소드 방식

 

위에 작성한 방식을 세터 메소드 방식으로 작성해 보겠습니다.

 

 

public class MemberRegisterService {

  private MemberDao memberDao;

  //세터로 주입하게 설정
  public void setMemberDao(MemberDao memberDao) {
  	this.memberDao = memberDao;
  }

  public void memberRegist(Member member) {
  	memberDao.insert(member);
  }
}

@Configuration
public class AppCtx {

	//스프링 빈 등록
	@Bean
	public MemberDao memberDao() {
		return new MemberDao();
	}
	
	//세터를 통해 주입
	@Bean
	public MemberRegisterService memberRegSvc() {
    	MemberRegisterService member = new MemberRegisterService();
        member.setMemberDao(memberDao());
		return member;
	}
 }

 

MemberRegisterService클래스에서 setter를 사용해서 memberDao를 setting 할 수 있게 해 줍니다.

AppCtx 클래스에서 memberRegSvc 메소드를 통해 bean을 만드는데 이때 MemberRegisterService클래스의 setter를 통해서 의존성을 주입하는 것을 알 수 있습니다.

 

반응형

 

그렇다면 생성자 방식세터 메소드 방식 중 어떤 것이 더 좋은 방법일까요?

정답은 "상황에 따라 다르다."입니다.

 

특징

 

  • 생성자 방식: 빈 객체를 생성하는 시점에 모든 의존 객체가 주입
  • 세터 메소드 방식: 세터 메소드 이름을 통해 어떤 의존 객체가 주입되는지 알 수 있다

 

따라서 객체를 생성하는 시점에 쉽게 의존성 주입을 하고 싶다면 생성자 방식을, 코드를 명확하고 알아보기 쉽게 사용하라면 세터 메소드 방식을 사용하는 것이 좋겠죠?

 

 

반응형

 

 

그럼 이러한 설정 파일을 두 개 이상 사용하려면 어떻게 해야 할까요?

 

앞서 나왔던 @Configuragtion와 @Autowired를 활용해 설정하는 방법이 있지만 @Autowired는 다음 포스팅에서 다룰 것이기 때문에 이 방법은 생략하겠습니다.

 

 

이외에도 @Import를 활용하면 두 개 이상의 설정 파일을 사용 가능하다고 합니다.

 

 

@Configuration
@Import({AppConf1.class, AppConf2.class})
public class AppConfImport {

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

 

위의 코드와 같이 설정 파일 안에 @Import 어노테이션으로 다른 설정 클래스들을 명시해 주면 하나의 클래스에서 여러 설정 파일들을 사용할 수 있습니다.

 

그렇다면 나중에 AnnotationConfigApplicationContext을 사용해서 스프링 컨테이너를 생성했을 때 AppConfImport.class만 불러온다면 AppConf1, AppConf2의 설정도 함께 사용해서 컨테이너를 초기화하는 것입니다.

 

 

반응형

 

 

이렇게 의존성을 주입하는 방법들을 배웠습니다만, 주입 대상 객체를 모든 bean 객체로 설정해야 할까요?

꼭 그런 것은 아닙니다. 그럼 빈으로 등록하지 않고 일반 객체로 생성하는 것과 빈 객체로 설정하는 것은 어떤 차이가 있을까요?

 

바로, 스프링 컨테이너가 객체를 관리하는지의 여부입니다. 겉으로 봤을 때 코드의 동작여부는 크게 다르지 않습니다.

하지만 스프링 컨테이너가 제공하는 자동 주입, 라이프사이클 관리 등 단순히 객체 생성외에도 객체를 관리하기 위한 다양한 기능을 제공하는데 이를 이용하기 위해서는 객체를 빈으로 등록해야 합니다. 그래서 이를 활용하기 위해서는 의존 주입 대상은 스프링 빈으로 등록해서 사용해야 합니다.

 

 

 

출처: 초보 웹 개발자를 위한 스프링 5 프로그래밍 입문

 

반응형
myoskin