inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

인프런 워밍업 스터디 클럽 0기 BE - 2주차 발자국

Aisha
0

강의 수강

스프링 컨테이너

클래스 안에 메소드를 생성해서 그것을 사용하기 위해선, 클래스를 "인스턴스화" 하는게 필요하다.

인스턴스화 한다는 건 간단히 말해서 붕어빵 틀(클래스)을 가지고 붕어빵을 만드는 거다.

지난 1주차에서는 UserController라는 클래스 안에서 api 진입지점으로 사용할 메소드들을 정의했었다.

 

그런데 강사님이 하라는대로 하긴했는데, 생각해보면 UserController를 인스턴스화 한적이 없다.

또한 mysql db와의 연결을 위해 jdbcTemplate이라는걸 사용했었는데,

이 템플릿을 파라미터로 가져와서 사용하려면 어딘가에서 jdbc템플릿이 정의되어있어야 할텐데

그런걸 한 적도 없다.

@RestController
public class UserController {
 private final UserService userService;


  public UserController(JdbcTemplate jdbcTemplate) {
    this.userService = new UserService(jdbcTemplate);
}
}

여기서 나오는 개념이 바로 스프링 컨테이너다.

@RestController의 역할은 크게 두 가지이다.

  1. UserController 클래스를 API의 진입 지점으로 등록

  2. UserController 클래스를 스프링 빈으로 등록

이 스프링 빈이라는 것이 스프링 컨테이너와 관계가 있다.

서버가 시작되면 자동으로 생성되는 것이 컨테이너 라는 건데, 이 컨테이너에

스프링 빈으로 등록된 클래스가 들어가게 된다. 또한 그 클래스의 인스턴스화도 함께 이뤄진다.

 

서버 시작 -> 기본 스프링 빈 등록 -> 개발자 설정 스프링 빈 등록 -> 해당 클래스들에게 필요한 의존성들이 자동 설정

 

따라서 UserController를 인스턴스화 해주지 않아도 메소드를 사용할 수 있었던 거다.

또한 jdbc템플릿도 이미 스프링 빈으로 등록되었기 때문에 우리가 따로 정의해놓지 않았지만

사용이 가능했다.

 

스프링 빈으로 굳이 왜 등록할까?

  1. 코드가 줄어드는 것 같다. -> 그닥 드라마틱하진 않다.

다양한 장점들이 있겠지만, 그냥 코드를 직접 짜는 입장에서 봤을 때는 인스턴스화를 new로 일일히 해주는게 귀찮았는데 스프링 빈으로 등록하면, 그냥 생성자에서 불러주기만 하면 돼서 좋은 것 같다.

  1. Repository에 변경사항이 생겼다고 가정할 때, service단의 변경도 필수가 된다. -> 이건 사고다

왜냐하면, 지금은 레포지토리를 부르는 게 한군데 밖에 없었지만 실제 현업에서는 레포지토리를 사용하는 코드 전부를 고쳐야 할 것이기 때문이다.

  1. 스프링 빈으로 등록하면, 컨테이너가 "의존성 주입"을 통해 변경된 레포지토리를 "선택"하도록 할 수 있다. -> 아주 좋다.

참고) 의존성 주입을 위한 어노테이션

참고) 스프링 빈 등록하는 어노테이션

문자열 sql 대신 JPA 사용하기

문자열 sql을 작성한 후, jdbctemplate을 이용해 mysql로 쿼리를 날리는 방식이 나쁘지 않다. 그런데 실제로 코드 짜면서 느낀거지만, 쿼리 하나가 좀 길다보니 간혹 오타를 낼 때 오류 잡는게 귀찮았다.

-> 실수를 런타임 때 발견하게 되어, 인지가 느리다.

또 sql의 문법이 문제다. sql을 만든 회사에 따라서 문법이 다 조금씩 다른데,

이럴일이 흔한지는 모르겠지만 Mysql을 쓰다가 갑자기 Mssql로 변경한다면

지옥일거다.

-> 문자열 sql 쿼리를 모두 수정하는 불상사가 발생

테이블에 칼럼이 5개만 해도 헷갈리는데, 그 이상이라고 한다면 데이터 하나당 테이블 칼럼으로 매칭해주는게 복잡해진다.

-> 귀찮고 복잡하다.

그래서 우리는 문자열 sql 대신 JPA를 사용할 수 있다.

JPA란 데이터를 영구적으로(영속성) 보관하기 위해 자바 진영에서 정해진 규칙이다. 쉽게 말해 이 JPA를 사용해 코드를 작성하면 객체와 관계형 db(mysql등등) 테이블을 짝지어 영구적으로 저장이 가능하다.

JPA를 사용하는 과정

  1. 최초에 JPA를 적용하기 위한 옵션 설정. jdbc사용을 위해 만들었던 application.yml 에 코드 추가.

  2. 테이블에 매핑되는 객체를 만들기. @Entity,@Id,@Column등 어노테이션 사용.


    주의) 기본 생성자 추가.

  3. 인터페이스를 만들고, jpaRepository를 상속받게 한다. 테이블의 매핑 객체와, 테이블 id의 타입을 넣어준다.

public interface UserRepository extends JpaRepository<User, Long> {
}
  1. 우리가 만든 인터페이스는 jparepository를 상속받았기 때문에, save나 findAll 등 기본 내장 메소드를 쓸 수 있다. 기본 메소드 외에 쓰고 싶으면, 이 인터페이스에 추가를 해주자.

     

     

    • 회고

     

     

     

    : 모든 개념을 공부할 때는 굳이?왜? 라는 의문을 가져봐야 할 것 같다. 굳이 스프링 빈을 왜 쓰는지, 그냥 인스턴스화 시키는것보다 스프링빈으로 등록하는 장점은 무엇인지 등등 말이다.


    : 일단 기본적인 기능완성에 초점을 두고, 더 좋은 코드. 더 효율적인 코드를 고민해보면서 다양한 어노테이션을 제대로 이해해야 겠다.

    미션

   public fruitNumResponse getFruitNum(String name){
        return new fruitNumResponse(fruitRepository.countByName(name));
    }

3번 문제는 쿼리로 들어온 option의 문자열을 가지고, if문 처리를 하는게 핵심이였다.

찾아보니 findByPriceGreaterThanEqual,findByPriceLessThanEqual 요런 메소드들이 있어서 쉽게 데이터를 뽑을 수 있었다.
(나중에 강사님 코멘트를 보니 enum이라는걸 활용하면 이렇게 문자열로 안해도 된다는데 확인해봐야겠다.)

 

그렇게 가져온 데이터들의 판매여부를 확인한 후, 판매되지 않은것만 가져와야 하기 때문에 false인 객체들만 notSellFruits에 담아 반환하도록 코드를 짰다.

public List<FruitListResponse> getFruitList(String option,Long price){
        Collection<Fruit> fruits;
        if(option.equals("GTE")){
            fruits = fruitRepository.findByPriceGreaterThanEqual(price);

        }else{
            fruits = fruitRepository.findByPriceLessThanEqual(price);
        }

        List<FruitListResponse> fruitList = fruits.stream().
                map(fruit1 -> new FruitListResponse(fruit1.getName(), fruit1.getPrice(),fruit1.getWarehousingDate(),fruit1.isSell()))
                .collect(Collectors.toList());

        List<FruitListResponse> notSellFruits = new ArrayList<>();

        for (FruitListResponse fruitListResponse : fruitList) {
           if(fruitListResponse.isSell()==false) {
               notSellFruits.add(fruitListResponse);

           }

        }
        return notSellFruits;


    }

답변 0