[Spring Boot] 의존성 주입과 스프링 빈 등록
의존성 주입과 스프링 빈 등록
DB에 사용자 정보를 넣고 빼기 위해 Service와 Repository를 만들었다.
이제 웹을 통해 접근할 수 있도록 Controller를 만들어줘야 한다.
MemberController.java
package com.devjaewoo.hellospring.controller;
import com.devjaewoo.hellospring.repository.MemoryMemberRepository;
import com.devjaewoo.hellospring.service.MemberService;
import org.springframework.stereotype.Controller;
@Controller
public class MemberController {
}
이제 Service 변수를 생성해야 한다. Java에서 했던 것처럼 아래와 같이 만들면 될까?
private final MemberService memberService = new MemberService(new MemoryMemberRepository());
아니다. MemberService는 MemberController 외에 다른 곳에서도 얼마든지 쓰일 수 있기 때문에
new로 선언하면 안 된다.
대신 생성자에 @Autowired라는 어노테이션을 통해 스프링 컨테이너에 있는
MemberService의 Bean을 찾아서 의존 관계 주입 (DI)을 해야 한다.
package com.devjaewoo.hellospring.controller;
import com.devjaewoo.hellospring.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class MemberController {
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
}
하지만 코드를 작성하면 아래와 같이 "Could not autowire, No beans of 'MemberService' type found."라는 에러 메시지가 뜬다.
@Autowired가 붙으면 해당 객체들을 스프링 컨테이너에서 빈으로 등록되어있는지 찾는데,
memberService가 스프링 빈에 등록되어있지 않기 때문이다.
스프링 빈을 등록하는 방법은 2가지가 있다.
- 컴포넌트 스캔과 자동 의존관계 설정
- Java 코드로 직접 스프링 빈 등록하기
컴포넌트 스캔과 자동 의존관계 설정
클래스 어노테이션에 @Component를 추가하면 자동으로 스프링 빈에 등록한다.
@Controller, @Service, @Repository 모두 @Component를 포함하는 어노테이션이기 때문에
각 클래스의 역할에 맞게 어노테이션을 달아주면 된다.
현재 MemberService 클래스가 Bean으로 등록되어 있지 않으니 @Service 어노테이션을 추가해주자.
MemberRepository도 @Autowired 해준다.
MemberService.java
@Service
public class MemberService {
private final MemberRepository memberRepository;
@Autowired
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
...
}
MemberRepository 변수에 발생한 에러 역시 @Repository 어노테이션을 붙여 해결해주면 자동 의존관계 설정이 끝난다.
MemoryMemberRepository.java
@Repository
public class MemoryMemberRepository implements MemberRepository {
...
}
현재 설정되어있는 구조를 아래의 그림처럼 표현할 수 있다.
Java 코드로 직접 스프링 빈 등록하기
실습을 위해 위의 수정사항에서 @Autowired는 남기고 @Service와 @Repository를 지워주자.
그다음 SpringConfig 클래스를 하나 만들고, @Configuration 어노테이션을 추가한다.
SpringConfig.java
package com.devjaewoo.hellospring;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
}
이제 SpringConfig 클래스에 Bean을 정의할 수 있다.
@Service와 @Repository를 제거했으니 이곳에 새로 만들어주자.
Bean 정의는 @Bean 어노테이션으로 할 수 있다.
SpringConfig.java
package com.devjaewoo.hellospring;
import com.devjaewoo.hellospring.repository.MemberRepository;
import com.devjaewoo.hellospring.repository.MemoryMemberRepository;
import com.devjaewoo.hellospring.service.MemberService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
@Bean
public MemberService memberService() {
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
이렇게 Component에 직접 어노테이션을 달아주지 않고 Config 파일에 Bean을 선언하면
처음엔 불편하지만 나중에 Bean 클래스를 교체할 때 생성할 다른 코드를 전혀 손댈 필요 없이
설정 파일만 바꿔주면 된다.
package com.devjaewoo.hellospring;
import com.devjaewoo.hellospring.repository.MemberRepository;
import com.devjaewoo.hellospring.repository.MemoryMemberRepository;
import com.devjaewoo.hellospring.service.MemberService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
@Bean
public MemberService memberService() {
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
// return new MemoryMemberRepository();
return new anotherMemberRepository();
}
}