본문 바로가기
JAVA & SPRING/Spring 입문

스프링 입문 강의 - 3일차 (스프링 빈, Controller)

by 눈오는1월 2023. 7. 18.
728x90

오늘 강의는 스프링 빈 과 의존관계 에 대해서 배웠다

 

Controller 패키지에 MemberController를 만들고 클래스 이름 위에 @Controller 어노테이션을 붙인다. 이 Controller 어노테이션이 있으면 스프링 컨테이너에 객체를 생성해서 스프링이 관리한다.(즉 컨트롤러는 스프링 컨테이너가 관리함)

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), 의존성 주입이라고 함 여기에서는 @AUutowired에 의해 스프링이 주입됨

 

이러고 실행시키면 Memberservice를 못찾는다는 오류가 나타나는데 Memberservice가 스프링 빈으로 등록되어있지 않기 때문에 못찾는다고 나타냄(helloController는 스프링이 제공하는 컨트롤러여서 스프링 빈으로 자동 등록됨)

그래서 우리는 이 memberService를 스프링 빈에 등록을 해줘야지 스프링을 실행시킬 수 있고, 스프링 빈으로 등록하는 방법은 크게 2가지가 있다.

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

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

 

1번 방식 원리로는 @Component 어노테이션이 있으면 스프링 빈으로 자동 등록해준다.(@Controller가 자동으로 스프링 빈으로 등록된 이유도 컴포넌트 스캔 때문)

@Component를 포함한 다른 어노테이션 종류 -> @Controller, @Service, @Repository

 

Memberservice code(회원 서비스 스프링 빈 등록)

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; // final은 한번만 사용할 수 있는 엔티티(데이터베이스 테이블과 매핑되는 자바 클래스) 정의할 때 사용

    //private final MemberRepository memberRepository = new MemoryMemberRepository();
    @Autowired // 스프링이 생성할때 생성자를 호출 -> 스프링 컨테이너에 있는 것을 넣어줌(주입)
    public Memberservice(MemberRepository memberRepository) {  // 직접생성하는것이 아닌 넣어주는 식으로
        this.memberRepository = memberRepository;
    } // 회원 리포지토리 코드가 회원 서비스 코드를 DI 가능하게 변경한다.

    /*
    * 회원가입
     */
    public Long join(Member member){
        // 같은 이름이 있는 중복 회원 x

        // Optional 안에 객체를 감쌈 null 일경우 Optional로 감쌈 꺼내고싶으면 get()쓰면됨
        // Optional로 바로 반환하는게 별로 좋지 않음
//        Optional<Member> result = memberRepository.findByName(member.getName());
//        result.ifPresent(m -> {
//            throw new IllegalStateException("이미 존재하는 회원입니다.");
//        })
        validateDuplicateMember(member);  // 중복회원검증
        memberRepository.save(member);
        return member.getId();
    }

    private void validateDuplicateMember(Member member) { // 위 중복회원 검증 메소드
        memberRepository.findByName(member.getName())  //결과가 바로 Optional 임
                        .ifPresent(m -> {
                            throw new IllegalStateException("이미 존재하는 회원입니다.");  // try catch 말고 이런식으로 예외처리가 가능
                        });
    }

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

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

}

2번 방식은 직접 자바코드로 스프링 빈을 등록하는 방식인데 SpringConfig라는 클래스를 java 폴더 내에 생성 (SpringApplication이랑 같은 위치에)

SpringConfig 코드

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

이번 강의에서는 2번째 방식을 사용한다. 그 이유는 현재 어떤 DataBase를 쓸지 아직 정하지 않았기 때문 

자바 코드로 직접 빈을 등록하면 디비를 정하더라도 생성자 생성할때 클래스만 벼경하면 되기때문에 수월함

추가로 스프링은 스프링 컨테이너에 스프링 빈을 등록할 때, 기본적으로 싱글톤으로 등록함

DI에는 필드 주입, setter 주입, 생성자 주입 이렇게 3가지가 있는데

필드 주입은 필드에 직접 @Autowired를 적는 방식인데 스프링에서 지향하고 있는 방식은 아님(외부에서 수정이 불가능 해서 객체를 수정하기 힘들다.)

또 setter주입 방식이 있는데 이 방식은 public메소드를 사용하게되므로 노출이 됨

요즘은 생성자를 통해서 주입하는 방식을 사용(외존관계가 실행중에 동적으로 변하는 경우가 거의 없음)

728x90