Back-End/Spring

[SpringBoot][스프링 입문] - 4.1 컴포넌트 스캔과 자동 의존관계 설정

얄루몬 2021. 12. 25. 07:45

1. 스프링빈과 의존관계

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

  • 회원 컨트롤러회원서비스와 회원 리포지토리를 사용할 수 있게 의존관계를 준비하자.
    • 화면을 붙이고 싶을 때 필요한 두 가지 : 컨트롤러 + 뷰 템플릿 (회원가입과, 회원가입을 위한 Html 파일)
    • 멤버서비스를 통해서 회원가입 멤버서비스를 통해서 데이터 조회할 수 있는 것을 의존관계가 있다고 한다. 

 

2. 인텔리제이 IS Never USED 경고가 뜰 땐 

 

 

[intelliJ] 인텔리J XXX is never used 경고 없애는 방법

intelliJ XXX is never used 경고 없애는 방법 intelliJ를 통해 개발을 하던 중 다음과 같이 Method 'xxx' is never used 라는 식의 경고를 보신적이 있으실 겁니다. 이는 class, field(필드), parameter(매개변수..

dololak.tistory.com

📌 이 티스토리를 참고하여 설정을 변경해주면 쉽게 처리 된다.

 

3. 정형화된 관계 설정(스프링 컨테이너 만들기) 

 

  • 스프링 컨테이너에 연결하기 위해서는 그저 자바클래스에 불과한 멤버 서비스에 서비스인 것을 알려주어야 하고 또한 리포지토리 또한 리포지토리인 것을 표시해서 알려야 한다.
  • 그리고 사용할 객체를 new 연산자를 통해서 생성하기 보다는 Autowired를 사용해서 스프링이 연결해서 1개로만 사용하고 관리할 수 있게 해야 한다. (이를 의존관계 설정이라고 한다.)

 

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

  • 컴포넌트 스캔 자동 의존관계 설정
    • @Service -> 서비스임을 알림
    • @Repository -> 레포지토리임을 알림
    • @Controller -> 컨트롤러임을 알림
      • 위의 항목들은 @Component를 포함하고 있다. 그렇기에 사용하기만 하면 자동으로 Spring bean으로 등록된다. 
    • Autowired -> 연관 관계 설정
  • 자바 코드로 직접 스프링 빈 등록하기

👉 두 가지 모두를 알아야 한다.

 

 

<스프링 빈(Bean)이란?>

  • Spring IOC 컨테이너가 관리하는 자바 객체를 빈(Bean)이라고 부른다. 
  • 이때 new 연산자를 통해서 객체를 생성하게 되면 new 연산자를 통해 생성된 객체는 빈이 아니게 된다.
  • 다시 말해서 Spring에서의 빈은 ApplicationContext가 알고 있는 객체 즉, ApplicationContext가 만들어서 그 안에 담고 있는 객체를 의미한다. 

톰캣에 연결 성공

위의 사진은 간단하게 컴포넌트 스캔 자동 의존관계 설정 하는 방식이다.

 

5. 무작정 Annotation 사용이 가능할까? 

< Annotation이란? >

  • Annotation은  @Component @Service @Repository @Controller 등과 같은 것들을 의미한다.
  • 또한 이들은 @Component @Service @Repository @Controller이 붙은 클래스 Bean을 찾아 Context에 Bean을 등록해주는 Annotation이다. 
  • 즉, 스프링 컨테이너에 빈을 등록해주는 기능을 한다.

 

< 무작정 Annotation 사용이 가능할까? >

  • 아무 클래스에 Annotation을 사용해서 Bean 등록을 해주는 것은 원칙적으로 불가능하다.
    • 왜냐하면 하위 패키지까지 전부 찾아서 등록하기 때문에 하위 패키지가 아니거나 하위 패키지가 동일하지 않은 경우엔 Bean으로 등록하지 않기 때문이다.(@ComponentScan)
    • 등록하고 싶다면 따로 등록은 가능하다.

 

6. Spring Bean 등록

  • 기본으로 싱글톤으로 등록한다. (싱글톤이란? 유일하게 등록해서 공유한다.)
    • 멤버 서비스는 멤버서비스 하나만, 멤버 리포지토리는 멤버리포지토리 하나만 이런식으로 등록하는 것을 싱글톤이라 한다.
    • 따라서 같은 스프링 빈이면 모두 같은 인스턴스이다. 
    • 설정으로 싱글톤이 아니게 설정은 가능하지만 특별한 경우를 제외하면 대부분 싱글톤을 사용한다.

 

7. Spring Bean에 컴포넌트 스캔 자동 의존관계 설정한 코드 

 

<컨트롤러 설정과 MemberService와의 연관 관계 설정>

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;
    }
}

 

<리포지토리 설정>

package hello.hellospring.repository;

import hello.hellospring.domain.Member;
import org.springframework.stereotype.Repository;

import java.util.*;

@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); //ID 세팅
        store.put(member.getId(),member); //스토어에 저장
        return member;
    }

    @Override
    public Optional<Member> findById(Long id) {
        return Optional.ofNullable(store.get(id)); //null여도 반환 가능
    }

    @Override
    public Optional<Member> findByName(String name) {
        return store.values().stream()
                .filter(member -> member.getName().equals(name))
                .findAny();

    }

    @Override
    public List<Member> findAll() {
        return new ArrayList<>(store.values());
    }

    public void clearStore(){
        store.clear();
    }

}

 

<서비스 설정과 멤버 리포지토리가 필요한 멤버 서비스를 연관 관계를 설정>

package hello.hellospring.service;

import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemberRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

@Service
public class MemberService {
    private final MemberRepository memberRepository;

    @Autowired //멤버 서비스는 멤버 리포지토리어가 필요
    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
        /*직접 new로 생성하는 것이 아닌 외부에서 넣어주게 해야
          같은 객체를 가르키고 있도록 할 수 있다. */
    }

    //회원가입
   public long join(Member member){
       //같은 이름이 있는 중복 회원 X
       validateDuplicateMember(member); //중복회원 검증

       memberRepository.save(member);
       return member.getId();
    }

    //refactoring 하는 단축키 ctrl + Alt + m (윈도우 기준)
    private void validateDuplicateMember(Member member) {
        memberRepository.findByName(member.getName())
                .ifPresent(m ->{ //null이 아닌 값이 있으면 !! -> Optional이라서 가능
                    throw new IllegalStateException("이미 존재하는 회원입니다.");
        } );
    }

    //전체 회원 조회
   public List<Member> findMembers(){
        return memberRepository.findAll();
    }

    public Optional<Member> findOne(Long memberId){
       return memberRepository.findById(memberId);
    }

}