본문 바로가기
3.1 SpringBoot/SpringBoot 강의정리

1-4 스프링 빈과 의존관계

by Dohi._. 2023. 5. 14.
728x90

목차 

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

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

 

 

 

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

스프링빈을 등록하고 의존관계설정하기

회원 컨트롤러가 회원서비스와 회원 리포지토리를 사용할 수 있게 의존관계를 준비하자.

 

회원 컨트롤러에 의존관계 추가

package hello.hellospring.controller;

import hello.hellospring.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class MemberController {
 private final MemberService memberService;
 
 @Autowired
 public MemberController(MemberService memberService) {
 this.memberService = memberService;
 }
}


생성자에 @Autowired이 있으면 스프링이 연관된 객체를 스프링 컨테이너에서 찾아서 넣어준다 이렇게 객체의존관계를 외부에서 넣어주는 것을 DI(Dependency Injection),의존성 주입이라 한다.

이전 테스트에서는 개발자가 직접주입했고 여기서는 @Autowired에 의해 스프링이 주입해준다.

 

 

@Autowired

어노테이션이 붙은 필드, 메서드, 생성자 등에 대해서 스프링 컨테이너는 자동으로 해당 타입의 빈(bean)을 찾아서 주입해줍니다. 이를 의존성 자동 주입(Dependency Injection by Autowiring)이라고 합니다.

@Autowired는 다음과 같이 사용 할수 있습니다

  1. 필드에 적용하기
  2. 생성자에 적용하기
  3. 메서드에 적용하기

의존성 자동 주입을 사용하면 코드의 의존성을 줄일 수 있어 유지보수성이 향상되고,

DI(Dependency Injection)를 적용하기 쉬워지는 등의 장점이 있습니다.

참고: 생성자에 @Autowired 를 사용하면 객체 생성 시점에 스프링 컨테이너에서 해당 스프링 빈을 찾아서 주입한다.
생성자가 1개만 있으면 @Autowired 는 생략할 수 있다

 

 

 


@controller가 있으면 
스프링 컨테이너 안에 컨트롤러 객체를 만들어놓습니다

Member Controller가 생성이 될 때, Spirng bin에 등록되어 있는 Member Service 객체를 가져다가 넣어줍니다
Autowired하면 스프링 컨테이너에서 가져는데!
처음에 에러가 뜨는 경우가 있을것이다

 

Consider defining a bean of type 'hello.hellospring.service.MemberService' in your configuration.

memberService가 스프링 빈으로 등록되어 있지 않다

helloController는 스프링이 제공하는 컨트롤러여서 스프링 빈으로 자동 등록된다. @Controller 가 있으면 자동 등록됨


순수한 자바코드에서는 아무것도 못가져오기에
@Service를 넣어줘서 스프링이 올라올때 service를 스프링 빈으로 등록해주도록 해야한다

Controller로 통해서 외부 요청을받고
Service: 비지니스 로직만들고
Repository :데이터 저장을하고 
정형화된 패턴이다

 

컴포넌트 스캔 원리

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

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

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

  • @Controller
  • @Service
  • @Repositor



스캔 범위

기본적으로 component  스캔의 범위는 @SpringBootApplication이 있는  SpringApplication의 패키지만을 스캔한다.

 

 

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

Spring에서는 여러 가지 Annotation(애노테이션)을 사용하지만,
Bean을 등록하기 위해서는 @Component을 사용한다.
@Component이 등록되어 있는 경우에는 Spring이 애노테이션을 확인하고 자체적으로 Bean 으로 등록한다.

 

회원 서비스 스프링 빈 등록

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

 

회원 리포지토리 스프링 빈 등록 

@Repository
public class MemoryMemberRepository implements MemberRepository {}

스프링 빈 등록 이미지예

memberService 와 memberRepository 가 스프링 컨테이너에 스프링 빈으로 등록되었다.

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

 


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

 

 

 

일단 회원 서비스와 회원리포지토리의 @service,@Repository,@Autowired 애노테이션제거  (컨트롤러는 그대로)

 

//@Service  (삭제)
public class MemberService {
    private final MemberRepository memberRepository;   //직접 주입하면 필드주입인데 필드 주입은 스프링이 안좋아하고 세터 주입이있는데 set으로 하는데 단점은 Public으로 열려있어야해서

    //@Autowired (삭제) 
    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
    /**
     * 회원가입
     */
    public Long join(Member member) {
        validateDuplicateMember(member); //중복 회원 검증 (컨알v)
        memberRepository.save(member);
        return member.getId();
    }

 

//@Repository (삭제)
public class MemoryMemberRepository implements MemberRepository {

    private static Map<Long,Member> store = new HashMap<>();
    private static long sequence = 0L;


    @Override
    public Member save(Member member) {
        member.setId(++sequence);
        store.put(member.getId(), member);
        return member;
    }

이제 직접 할것입니다 

SpringConfig라는 클래스 생성 
@Configuration 붙여줍니다

package hello.hellospring;
import hello.hellospring.repository.MemberRepository;
import hello.hellospring.repository.MemoryMemberRepository;
import hello.hellospring.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();
 }
}

왜 컨트롤러는 왜 직접안하나 
컨트롤러는 스프링이 오차피 관리하는 아이기 때문에 그대로 쓴다.

지금 직접 자바코드로 빈을 설정하는지?
지금 리포지트리를 변경하려고 하는 컨셉이기때문에 (메모리저장방식은 임시)
컴포넌트 스캔 방식대신에 자바코드로 빈을 설정하는중이다.

자바코드로 직접 설정하지않고 예전에는 XML로 설정하는 방식도 썻다고한다
DI에는 필드주입 setter주입 생성자 주입 이렇게 3가지 방법이 있다 
의존관계가 실행중에는 동적으로 변하는 경우가 거의 없으므로 생성자 주입을 권장한다.

생성자
처음에 생성하는 시점에만 호출하고 그이후로는 막아버림

필드
필드자체를 @autowired를 하는건데 (중간에 바꿀수 없는 단점이 있어서 비권고)

 

새터
단점:누군가가 호출했을때 public으로 있어야해서 
굳이 public으로 할 이유가 없는 것을 public으로 오픈되어있어서 잘안씀
아무개발자나 다 호출할수있도록 오픈되어있어서 


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

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

 

728x90

댓글