본문 바로가기

Spring

스프링 빈과 의존 관계 설정

외부 요청을 받는 Controller는 비즈니스 로직을 만드는 Service를 의존하고 Service는 데이터를 저장한 Repository를 의존한다. 이것이 기본적으로 정형화된 패턴이다.

 

스프링 빈을 등록하는 2가지 방법

-컴포넌트 스캔과 자동 의존관계 설정

-자바 코드로 직접 스프링 빈 연결

 

 

컴포넌트 스캔과 자동 의존관계 설정

@Component : 애노테이션이 있으면 스프링 빈으로 자동 등록된다.

@Controller : 컨트롤러가 스프링 빈으로 자동 등록된 이유도 컴포넌트 스캔 때문이다.

 

컴포넌트를 포함하는 다음 애노테이션도 스프링 빈으로 자동 등록된다.

@Controller 

@Service

@Repository 

 

스프링이 실행될때 컴포넌트 관련 애노테이션이 있다면 스프링이 객체로 생성시켜 스프링 컨테이너에 등록한다.

@Autowired는 연관관계를 연결시켜 사용할 수 있다.

 

스프링이 실행될때 @SpringBootApplication부터 시작한다.

동일한 패키지거나 하위 패키지가 아닌 패키지들은 스프링 빈으로 컴포넌트 스캔을 하지 않는다. (따로 *@ComponentScan 설정을 하면 가능은 하지만 기본적으로는 컴포넌트 스캔의 대상이 되지않는다.) 

 

#참고 : 스프링은 스프링 컨테이너에 스프링 빈을 등록할 때, 기본적으로 싱글톤으로 등록한다(유일하게 하나만 등록해서 공유) 따라서 같은 스프링 빈이면 모두 같은 인스턴스이다. 설정으로 싱글톤이 아니게 설정할 수 있지만, 특별한 경우를 제외하면 대부분 싱글톤을 사용한다. 

 

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

 

package com.example.spring;

import com.example.spring.repository.MemberRepository;
import com.example.spring.repository.MemoryMemberRepository;
import com.example.spring.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();
    }
}

   기존 컴포넌트 애노테이션을 지우고 (@Service @Repository @ Autowired)

spring 패키지에 SpringConfig라는 자바 클래스를 만든 후 @Configuration이라는 애노테이션을 붙인 후 @Bean이라는 애노테이션을 메소드에 붙이면 그 메소드로 인해 스프링 빈을 등록할 수 있다.

 

#참고 : DI(dependency injection : 하나의 객체가 다른 객체의 의존성을 제공하는 테크닉)에는 필드 주입, setter 주입, 생성자 주입 이렇게 3가지 방법이 있다. 의존관계가 실행중에 동적으로 변하는 경우는 거의 없음으로 생성자 주입을 권장한다.

 

@Controller
public class MemberController {

   @Autowired private MemberService memberService;
} //필드 주입 방법 : 별로 안좋은 방법이다. 중간에 변경할 수 있는 방법이 아예 없다

@Controller
public class MemberController {

    private MemberService memberService;

    @Autowired
    public void setMemberController(MemberService memberService) {
        this.memberService = memberService;
    }
} //set : 누군가가 컨트롤러로 호출했을때 public으로 열려있어야 한다. 노출이 되어있어 중간에 쉽게 변경하면 문제가 생길 수 있다. 


@Controller
public class MemberController {

    private final MemberService memberService;

    @Autowired
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }
}  //생성자 주입 방법 조립시점에만 생성하고 변경을 못하도록 막을 수 있어 유용하다.

 

#참고 : 실무에서는 주로 정형화된 컨트롤러, 서비스, 리포지토리 같은 코드는 컴포넌트 스캔을 사용한다. 그리고 정형화 되지 않거나, 상황에 따라 구현 클래스를 변경해야 하면 설정을 통해 스프링 빈으로 등록한다.

 

#참고 : @Autowired를 통한 DI는 스프링이 관리하는 객체에서만 동작한다. 스프링 빈으로 등록하지 않고 내가 직접 생성한 객체에서는 동작하지 않는다.

 

'Spring' 카테고리의 다른 글