상세 컨텐츠

본문 제목

[Spring] 스프링 빈과 의존관계. (컴포넌트 스캔과 자동 의존관계 설정/자바 코드로 직접 스프링 빈 등록하기)

개발 공부/Spring

by 양양츄 2024. 3. 4. 16:47

본문

스프링을 실행하면 package hello.hellospring.controller; 경로에 있는 controller를 확인한다.

service를 사용하는데, service에 알맞는 스프링 빈이 없으면 에러가 발생한다.

 

스프링 빈이 잘 등록되어 있다면 아래와 같은 구조로 스프링은 동작한다.

 

그렇다면, 스프링 빈은 어떻게 등록하는가??

아래에서 알아보자.

 

 

 

스프링에서 빈(bean) 등록하는 방법에는 2가지가 있다.

 

1. 컴포넌트 스캔과 자동 의존관계 설정 ( @ComponentScan, DI(Dependency Injection) )

컴포넌트 스캔은 클래스를 스프링 빈에 등록해주는 역할을 한다.

@Component 어노테이션이 있으면 해당 클래스는 스프링 빈으로 자동 등록된다.

어라?? 학원에서 공부할때나 영상에서는 @Component를 안쓰던데..?

@Controller @Service @Repository 같은것만 쓰던데...?

맞다.

@Controller @Service @Repository  에 @Component 어노테이션이 포함(내장)되어 있다.

그래서 @Controller @Service @Repository 로 각각의 클래스의 역할을 나누어서 스프링 빈으로 등록해두고

필요한 객체를 생성할때 @Autowired를 사용해서 스프링 컨테이너에서 일치하는 빈 을 찾아서 연결해준다.

 


@Service
public class MemberService {

    //생성자를 직접 생성해보자.
    private final MemberRepository memberRepository = new MemoryMemberRepository();

}

위의 코드에서 new 연산자를 사용해서 MemoryMemberRepository() 객체를 직접 생성했다.
하지만, 스프링은 스프링 컨테이너가 등록된 빈(Bean)을 관리한다.



아래의 코드는 생성자를 직접 생성하지 않고, @Autowired 어노테이션을 사용해서
스프링이 스프링 컨테이너에서 선언된(private final MemberRepository memberRepository;) 객체를
외부에서 넣어준다. 주입한다. => Dependency Injection
인텔리제이(Intellij)에서는 alt+insert 키를 누르면 DI를 할 수 있는 객체가 있는지, 있다면 직접 생성해준다.

@Service
public class MemberService {
	
    //직접 생성하지 않고, 외부에서 주입받아 보자. DI
    private final MemberRepository memberRepository;

    //DI 완료
    @Autowired
    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
}

 

 

2. 자바 코드로 직접 스프링 빈(Bean) 등록하기

@Configuration 어노테이션을 사용해서 직접 스프링 빈을 등록할 수 있다
@Bean 어노테이션을 사용해서 메서드를 스프링 빈에 등록할 수 있다.

@Controller
public class MemberController {

    private final MemberService memberService;

    @Autowired //생성자
    //@Autowired 를 사용하면, 스프링이 스프링컨테이너에서 관리하는 항목중에 일치하는것을 가져와서 알아서 사용함
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }
}


public class MemberService {

    //직접 생성하지 않고, 외부에서 주입받아서 써보자. DI
    //private final MemberRepository memberRepository = new MemoryMemberRepository();
    private final MemberRepository memberRepository;

    //DI 완료
    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
}

1번 방법과 다르게, 자바 코드로 직접 스프링 빈을 등록해보자.
@Service 어노테이션이 없기 때문에 위 클래스는 스프링 빈에 등록되어 있지 않다.
그렇기 때문에 @Controller 어노테이션이 있는 클래스에서 MemberService와 MemberRepository를 연결 받을 수 없다.



@Configuration 어노테이션을 사용해서 직접 스프링 빈을 등록해보자.
@Bean 어노테이션을 사용해서 메서드를 스프링 빈에 등록할 수 있다.
MemberService는 구현체 memberRepository()를 매개변수로 받도록 => service는 repository를 인자로..
MemberRepository는 인터페이스는 생성할 수 없으니 구현체 MemoryMemberRepository()를 반환한다.
이렇게 service와 repository를 스프링 빈에 직접 등록할 수 있다.

@Configuration
public class SpringConfig {

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

    @Bean
    public MemberRepository memberRepository() {
        return new MemoryMemberRepository(); /* 구현체 MemberRepository 를 생성한다.
                                             => public class MemoryMemberRepository implements MemberRepository
                                             인터페이스는 new 할수없기 때문에. MemberRepository 는 interface 이기 때문이다.
                                             ==> 즉, 인터페이스는 new 불가 / 구현체는 new 가능
                                             */
    }
}

관련글 더보기