본문 바로가기
공부/Spring

[Spring][인프런 스프링 입문] 스프링 빈과 의존 관계

by 웅대 2022. 12. 29.
728x90
반응형

본 포스팅은 김영한 강사님의 인프런 강의 "스프링 입문"을 정리한 포스팅으로 강의 자료에서 사용한 자료를 사용했음을 밝힙니다.

 

웹 애플리케이션 계층 구조와 클래스 의존 관계는 아래 그림과 같다.

 

클래스 의존 관계에서 MemberRepository가 interface로 구현되어있는 이유는 데이터베이스와 같은 저장소를 아직 선정하지 않은 상황을 가정했기 때문이다.

테스트를 위해서 인터페이스를 상속받아 임시로 Memory 기반의 레포지토리를 생성하는 것을 의미한다.

 

실제 구현은 아래와 같다.

 

먼저 멤버 도메인을 getter와 setter를 사용하여 구현한다.

public class Member {
    private long id;
    private String name;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Alt + Insert를 누르면 손쉽게 getter와 setter를 추가할 수 있다.

 

그 다음 레포지토리 interface를 구현한다.

public interface MemberRepository {
    Member save(Member member);
    Optional<Member> findById(long id);
    Optional<Member> findByName(String name);
    List<Member> findAll();
}

임시로 메모리 레포지토리를 구현한다.

public class MemoryMemberRepository implements MemberRepository{

    private static Map<Long, Member> store = new HashMap<>();
    private static long sequence = 0L;
    @Override
    public Member save(Member member) {
    	//저장
    }

    @Override
    public Optional<Member> findById(long id) {
        //id 검색
    }

    @Override
    public Optional<Member> findByName(String name) {
    	//이름 검색
    }

    @Override
    public List<Member> findAll() {
   
   		//모든 멤버 검색
    }

    public void clearStore(){
        //초기화
    }
}

이제 서비스를 만들어야한다.

 

서비스에서도 레포지토리가 필요한데 이를 서비스 클래스 내부에서 아래와 같이 만들어도 되지만

private final MemberRepository memberRepository = new MemoryMemberRepository();

아래와 같이 외부에서 레포지토리를 생성해서 넣어주는 편이 좋다.

private final MemberRepository memberRepository;
public MemberService(MemberRepository memberRepository) {
 	this.memberRepository = memberRepository;
 }

이렇게 구현할 경우 외부에서 의존 관계를 주입할 수 있다. (Dependency Injection)

 

이렇게 구현할 경우 많은 장점이 존재하는데 그 중 하나가 테스트에 용이하다는 점이다.

 

스프링 빈과 의존 관계

스프링에서는 controller와 service와 repository를 스프링 컨테이너에 스프링 빈으로 등록해야 스프링이 자동으로 의존 관계를 주입할 수 있다.

 

두 가지 방법이 존재한다.

 

1. 어노테이션(Annotation) 사용 (컴포넌트 스캔 방식)

 

컨트롤러, 서비스, 레포지토리 각각의 클래스 앞에 Controller, Service, Repository라는 어노테이션을 달아주면 된다.

@Controller
public class HelloController {
.
.
.
}
@Service
public class MemberService {
.
.
.
}
@Repository
public class MemoryMemberRepository implements MemberRepository{
.
.
.
}

 

 

이제 서비스 코드에서 Autowired 어노테이션을 달아주면 된다.

 

@Service
public class MemberService {
    private final MemberRepository memberRepository;
    @Autowired
    public MemberService(MemberRepository repository) {
        this.memberRepository = repository;

    }
 }

이렇게 Autowired 어노테이션을 달아주면 스프링이 객체를 자동으로 스프링 컨테이너에서 찾아서 넣어준다. (Dependency Injection)

 

2. 자바 코드로 직접 등록

 

1번 방식과 달리 어노테이션을 달지 않고 직접 등록하는 방법이 존재한다.

@Configuration
public class SpringConfig {
    @Bean
    public MemberService memberService(){
        return new MemberService(memberRepository());
    }

    @Bean
    public MemberRepository memberRepository(){
        return new MemoryMemberRepository();
    }
}

이렇게 따로 파일을 만들어서 위와 같은 방식으로 직접 등록할 수 있다.

 

처음에 아직 어떠한 저장소를 사용할 지 알지 못하기 때문에 인터페이스로 구현을 하고 임시로 메모리 기반의 레포지토리를 만들었다.

 

그런데 나중에 저장소를 결정하고 실제 사용할 RealMemberRepository라는 이름의 레포지토리를 만들었다고 해보자.

 

자바 코드로 직접 스프링 빈에 등록하는 방식을 택했다면 레포지토리를 변경할 때 한 줄만 바꿔주면 된다.

@Configuration
public class SpringConfig {
    @Bean
    public MemberService memberService(){
        return new MemberService(memberRepository());
    }

    @Bean
    public MemberRepository memberRepository(){
        return new RealMemberRepository();
    }
}

위와 같이 MemoryMemberRepository를 RealMemberRepository로 바꿔주면 된다.

728x90
반응형

댓글