Spring Boot_자바 코드로 직접 스프링 빈 등록하기

이세미·2023년 5월 14일
0

SpringBoot

목록 보기
13/23
post-thumbnail

자바 코드로 직접 스프링 빈 등록하기

  • 기존에 작성하였던 회원 서비스와 회원 리포지토리의 @Service, @Repository, @Autowired 애노테이션을 제거하고 진행한다.
    *MemberController는 그대로 놔둔다.

스프링 빈을 직접 등록하는 코드를 작성하기 위해 main - java - hellospring - service 밑에 SpringConfig 클래스를 하나 생성하였다.

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

우선 @Configuration를 해주고,
Spring Bean을 등록할 거라는 의미로 @Bean을 해준다.

위 코드를 작성하면
스프링이 Contiguration을 읽고,
스프링 빈에 등록하라는 뜻으로 이해한다.

그리고 memberService 로직을 호출해서 등록을 해준다.

근데 return new MemberService();부분에서 생성자에 뭘 넣어줘야 하는데,
뭘 넣어줘야 하는지 명령어 command + p 로 확인을 해 보면, MemberRepository라고 뜬다.
따라서

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

MemberRepository를 등록을 해주고,
MemberRepository는 인터페이스이기 때문에 new 가 안되므로
구현체인 MemoryMemberRepository를 return 해준다.

그 다음
MemberService에는 MemberRepository를 엮어주어야 하기 때문에

 public MemberService memberService(){
        return new MemberService(memberRepository(memberRepository));
    }

MemberService 부분에 memberRepository를 넣어준다.

결론적으로

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

memberService와 memberRepository를
둘 다 스프링 빈에 등록을 해주고,
스프링 빈에 등록되어 있는 memberRepository를
memberService에 등록 해주면서 완성되는 것이다.

Controller는 스프링이 어차피 관리하는 것이기 때문에 그대로 두면,
Autowired가 그냥 알아서 해준다.

run을 시켜보면,

정상적으로 실행이 되는 것을 볼 수 있다.

이렇게 컴포넌트 스캔과 자동 의존관계 설정 방법과,
이번에 진행했던 자바 코드로 직접 스프링 빈 등록하는 방법
두 가지를 다 진행해보았다.


DI에는 필드 주입, setter 주입, 생성자 주입 세 가지 방법이 있다.

먼저 생성자 주입 방법은,

@Controller
public class MemberController {

    private final MemberService memberService;

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

작성했었던 Controller 코드와 같이, 생성자를 통해서 memberService가 MemberController에 주입이 되는 것이다.

필드 주입 방법
은,

@Controller
public class MemberController {

    @Autowired private MemberService memberService;

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

아예 생성자를 빼고 필드에 Autowired를 해주는 것이다.

하지만 이 방법은 별로 좋지 않은 방법이다.

그 다음이 setter 주입 방법인데,

@Controller
public class MemberController {

    private MemberService memberService;

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

이런 식으로 command + n 단축키를 이용하여 setter을 생성하고,
@Autowired를 해주면 된다.

이 방법의 단점은
누군가가 memberController을 호출했을 때 setMemberService가 public으로 항상 노출이 되어 있어야 한다는 것이다.

의존 관계가 실행중에 동적으로 변하는 경우는 거의 없으므로,
제일 권장하는 방법은
처음에 했던 생성자 주입 방법이다.

참고) 실무에서는 주로 정형화된 controller, service, repository 같은 코드는 컴포넌트 스캔을 사용한다.

정형화된 코드란 일반적으로 작성하는 controller, service, repository를 말한다.

정형화되지 않거나 상황에 따라 구현 클래스를 변경해야 하면 설정을 통해 스프링 빈으로 등록한다(중요).

---->
memberRepository를 설계할 때, 아직 데이터 저장소가 선정되지 않았다는 가상의 시나리오가 있었다.

때문에 일단 메모리를 만들고 나중에 교체하자고 했었다.

그래서 interface MemberRepository를 설계 하고,
Memory MemberRepository를 구현체로 만들었던 것이다.

그런데 MemoryMemberRepository를 이제 database에 실제로 연결하는 repository로 바꿀 것이다.

바꿔치기 할 때 기존의 MemberService나 나머지 코드에 하나도 손 대지 않고 바꿀 수 있는 방법이 있다.

이 방법이 무엇이냐면,

아까 작성하였던 SpringConfig의

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

위 코드에서,

return new DbMemberRepository();

이 부분만 DbMemberRepository();로 바꿔주면 dataBase에 연결할 수 있게 되는 것이다.

다른 부분은 전혀 손댈 필요가 없다.

이것이 직접 코드로 작성할 때의 장점이다.
컴포넌트 스캔을 사용하면,
여러 코드를 바꿔야 하는 단점이 있다.

주의사항은
@Autowired를 통한 DI는 helloController, MemberService 등과 같이 스프링이 관리하는 객체에서만 동작한다. 스프링 빈으로 등록하지 않고 내가 직접 생성한 객체에서는 동작하지 않는다.

0개의 댓글