ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 인프런 스프링 입문 06 / 스프링 빈 등록 2 가지
    스프링&스프링부트 2022. 12. 4. 15:45

    스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술


    스프링 빈과 의존관계

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

        > 컴포넌트 스캔과 자동 의존관계 설정

            > 컴포넌트 스캔 원리 : @Component 애노테이션이 있으면 스프링 빈으로 자동 등록

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

     

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

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

    package hello.hellospring.controller;
    
    import hello.hellospring.service.MemberService;
    import org.springframework.stereotype.Controller;
    
    @Controller
    public class MemberController {
    
        private final MemberService memberService = new MemberService();
    
        }
    
    }

     

    - controller 생성 > 스프링 컨터이너에 controller 생성

    - MemberController 제외한 다른 controller에서도 MemberService를 사용

    - MemberService에는 특별한 기능이 없기 때문에 new 객체 생성해서 사용하는 것은 별로

    - 스프링 컨테이너에 등록하고 계속 사용하는 것이 낫다 > @Autowired 사용 (연결 역할)

     

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

     

    - MemberController에서 오류 발생 :

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

        > MemberService는 순수한 java class이기 때문에 스프링이 알아볼 수 있는 방법이 없음

        > MemberService에 @Service 어노테이션 추가

        > MemoryRepository에 @Repository 어노테이션 추가

     

    - @Autowired

        > MemberController가 생성될 때 스프링 컨테이너에 등록되어있는 MemberService에 객체를 넣어준다

        > 객체 의존관계를 외부에서 넣어주는 것 : DI (Dependency Injection, 의존관계 주입)

     

     

    @Service
    public class MemberService {
    
        private final MemberRepository memberRepository;
    
        @Autowired
        public MemberService(MemberRepository memberRepository) {
            this.memberRepository = memberRepository;
        }
    
        //회원 가입
        public long join(Member member) {
            validateDuplicateMember(member);
            memberRepository.save(member);
            return member.getId();
        }
    }

     

    - @Autowired

        > MemberService 객체 생성 시점에 스프링 컨테이너에서 해당 스프링 빈을 찾아서 주입

        > MemoryMemberRepository (구현체)를 service에 주입

        > controller - service - repository 모두 연결 완료

     

     

    - 스프링 빈 등록 이미지

    - 참고:

    스프링은 스프링 컨테이너에 스프링 빈을 등록할 때, 기본으로 싱글톤으로 등록 (유일하게 하나만 등록해서 공유)

    따라서 같은 스프링 빈이면 모두 같은 인스턴스다. 설정으로 싱글톤이 아니게 설정할 수 있지만, 특별한 경우를 제외하면 대부분 싱글톤을 사용한다.

     

     

    싱글톤 패턴?

    - 객체의 인스턴스가 오직 1개만 생성되는 패턴

        > 장점 1. 메모리 : 최초 한 번의 new 연산자를 통해 고정된 메모리 영역을 사용하기 때문에 해당 객체에 접근할 때 메모리 낭비를 방지할 수 있고 속도도 빠르다

        > 장점2. 데이터 공유가 쉬움 : 싱글톤 인스턴스가 전역으로 사용되는 인스턴스이기 때문에 다른 클래스의 인스턴스들이 접근하여 사용하기 쉽다

        > 단점1. 싱글톤 패턴을 구현하는 코드 자체가 많이 필요

        > 단점2. 테스트하기 어려움

    >> 싱글톤 패턴은 단독으로 사용하면 객체지향에 위반되는 경우가 많다.

    >> 스프링 컨테이너와 같은 프레임 워크의 도움을 받으면 문제점들을 보완하면서 장점만을 이용 가능

    >> 스프링 빈은 컨테이너의 도움을 받아 싱글톤 스콥으로 관리되고 있다

     

     

     

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

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

     

     

    - DI 3가지

        > 의존관계가 실행 중에 동적으로 변하는 경우는 거의 없으므로 생성자 주입을 권장한다.

    1. 필드 주입

    public class MemberController {
    	@Autowired private MemberService memberService;
    }

     

    2. setter 주입

    public class MemberController {
    	private MemberService memberService;
        
        @Autowired
        public void setMemberService(MemberService meberService) {
        	this.memberService = memberService;
        }
    }

     

    3. 생성자 주입

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

     

     

    - 참고:

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

     

     

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

     

     

     

     

     


    * 자바 기초를 다시 공부해야겠다는 생각이 든다...

    ( 참고 )

    https://tecoble.techcourse.co.kr/post/2020-11-07-singleton/

     

    728x90
Designed by Tistory.