본문 바로가기

컴퓨터/Spring Boot

[TIL] Spring Boot(intellij) - 스프링 빈과 의존 관계

* 인프런 김영한 강사님의 스프링 입문 강의 정리

회원 컨트롤러가 회원 서비스와 리포지토리를 사용할 수 있으려면

그들 사이를 엮어주는 무언가가 필요하고 

이 때 사용하는 것이 바로 스프링 빈이다.

 

스프링 빈을 등록하는 방법은 컴포넌트 스캔과 직접 코드로 등록하는 두 가지 방법이 있다.

 

1. 컴포넌트 스캔

- 컴포넌트 스캔은 @Component 어노테이션이 있으면 스프링 빈으로 자동 등록된다.

- @Controller, @Service, @Repository 등은 @Component를 포함하므로 스프링 빈으로 자동 등록된다.

 

[controller]

@Controller
public class MemberController {
	...
}

[service]

@Service
public class MemberService {
	...
}

[repository]

@Repository
public class memoryMemberRepository implements memberRepository{
	...
}

 

2. 직접 스프링 빈 등록

직접 코드로 스프링 빈을 등록할 시에는 컴포넌트 스캔 시 사용했던 어노테이션을 제거해야한다.

다음과 같이 SpringConfig 파일을 만들고 @Configuration 어노테이션을 사용한다.

그리고 @Bean 어노테이션으로 회원 서비스, 회원 리포지토리를 각각 스프링 빈에 등록한다.

스프링 빈을 직접 구현하면 상황에 따라 구현 클래스를 변경할 때

SpringConfig 파일에서 관리가 가능하다.

 

따라서 예제에서는 현재 db설정을 하지 않았고 이후 설정한 db로 리포지토리를 변경해야 하기 때문에

컴포넌트 스캔 대신 자바 코드로 스프링 빈을 등록한다.

 

package myStudyspring.myStudyspring;

import myStudyspring.myStudyspring.repository.memberRepository;
import myStudyspring.myStudyspring.repository.memoryMemberRepository;
import myStudyspring.myStudyspring.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();
    }
}

 


 

스프링은 스프링 빈을 등록할 때 싱글톤으로 등록한다. 

같은 스프링 빈을 사용한다면 같은 인스턴스이다.

싱글톤?
- 객체의 인스턴스가 오직 1개만 생성되는 패턴
- 메모리 낭비를 방지하고 데이터 공유에 용이하다.
- 동시성 문제, 테스트 어려움 등의 문제가 있다.
(프레임 워크의 도움을 받으면 보완 가능하다.)

 


 

스프링 빈이 생성되면 의존성을 주입해야 한다.

스프링 빈으로 등록한 후

@Autowired 어노테이션을 사용하면 스프링이 관련 객체를 찾아 의존성을 주입(DI: Dependency Injection)한다.


@Controller
public class MemberController {

    //new로 객체를 생성할 필요 없이 스프링 컨테이너에서 가져다 쓰면 된다.
    private final MemberService memberService;

    @Autowired
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }
}

 

DI에는 

1. 필드 주입

2. setter 주입

3. 생성자 주입

의 3가지 방법이 있다.

 

[필드 주입]

- 중간에 변경이 어려우므로 권장 x

@Controller
public class MemberController {
	
    //필드 주입
    @AutoWried
    private MemberService memberService;

}

 

[setter 주입]

- public 으로 열려있어야 하므로 누구나 호출 가능하여 노출될 위험이 있다.

- 호출하지 않아도 될 메서드를 호출할 가능성이 있다.

- 권장 x

@Controller
public class MemberController {
    //세터 주입
    private MemberService memberService;

    @Autowired
    public void setMemberService(MemberService memberService) {
        this.memberService = memberService;
    }
  
}

 

[생성자 주입]

- 의존 관계가 실행 중 동적으로 변하지 않으므로 권장

@Controller
public class MemberController {
    //생성자 주입
    private final MemberService memberService;
    
    @Autowired
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }
}

 

 

실무 프로젝트를 경험할 당시

어떤 분은 필드 주입을 사용하고 어떤 분은 생성자 주입을 사용하였다.

그 둘의 차이에 대하여 명확하게 이해가 가지 않았는데

이번 학습을 통해 필드 주입과 세터주입 그리고 생성자 주입을 구분하고 장단점을 알게 되었다.

어떤 코드가 좋은 코드인지 하나 하나 배워 가는 것 같다.

728x90