20220529 WIL

Don Lee·2022년 5월 29일
0

EpiTIL

목록 보기
18/24

Controller, Service, Repository를 가게로 치면?

  • Controller: 가게 홀 직원. 손님을 응대하고 주문을 받아 카운터로 넘김
  • Service: 카운터 직원. 홀 직원의 주문을 받아 주방으로 넘김. 반대로 주방에서 카운터 직원에게 음식을 내줌. 사장이 그 역할을 하는 경우가 많으며 가게를 운영하기 위한 기타 사항을 다루기 때문에 가장 중요하다.
  • Repository: 음식을 만드는 사람.

@Configuration & @Bean & @Component & @IoC Container

  • @Configuration: 스프링 IOC Container에게 해당 클래스를 Bean 구성 Class임을 알려주는 어노태이션.
  • @IoC Container: 스프링 애플리케이션에서는 오브젝트의 생성과 관계설정, 사용, 제거 등의 작업을 애플리케이션 코드 대신 독립된 컨테이너가 담당한다. 이를 컨테이너가 코드 대신 오브젝트에 대한 제어권을 갖고 있다고 해서 IoC라고 부른다. 그래서 스프링 컨테이너를 IoC 컨테이너라고도 한다. - 토비의 스프링3.0 767p
  • @Component & @Bean: @Bean어노테이션과 @Component어노테이션 둘다 Spring(IOC) ContainerBean을 등록하도록 하는 메타데이터(실제 데이터가 아닌 데이터를 위한 데이터)를 기입하는 어노테이션이다. 그렇다면 왜 두개나 만들어 놓았을까? 정답은 둘의 용도가 다르기 때문이다.

BeanComponent
메소드에 사용클래스에 사용
개발자가 컨트롤이 불가능한외부 라이브러리 사용시 사용개발자가 직접 컨트롤이 가능한내부 클래스에 사용
  • @Bean: 메소드 레벨에서 선언하며, 반환되는 객체(인스턴스)를 개발자가 수동으로 빈으로 등록하는 애노테이션. 개발자가 컨트롤이 불가능한 외부 라이브러리들을 Bean으로 등록하고 싶은 경우에 사용된다.

    우리가 new 연산자로 어떤 객체를 생성했을 때 그 객체는 Bean 아니다.ApplicationContext.getBean()으로 얻어질 수 있는 객체는 Bean이다.

    @Configuration
    public class ApplicationConfig {    
        @Bean
        public ArrayList<String> array(){
            return new ArrayList<String>();
        }   
    }

    위는 @Bean어노테이션을 이용하여 Bean을 생성한 예제이다. 위와 같이 ArrayList같은 라이브러리등을 Bean으로 등록하기 위해서는 별도로 해당 라이브러리 객체를 반환하는 Method를 만들고 @Bean어노테이션을 붙혀주면 된다. 위의 경우 Bean어노테이션에 아무런 값을 지정하지 않았으므로 Method 이름을 CamelCase로 변경한 것이 Bean id로 등록된다. (ex. 메소드 이름이 arrayList()인 경우 arrayList가 Bean id)

    @Configuration
    public class ApplicationConfig {    
            
        @Bean
        public ArrayList<Integer> array(){
            return new ArrayList<Integer>();
        }   
        
        @Bean
        public Student student() {
            return new Student(array());
        }
    }

    의존관계가 필요할 때에는 어떻게 해결할 수 있을까? Student객체의 경우 생성자에서 ArrayList를 주입 받도록 코드를 짜놓았다 이럴때에는 Bean으로 선언된 array()메소드를 호출함으로써 의존성을 주입할 수 있다.

    그러면 왜 @Bean을 사용하는가? 메소드가 아닌 그냥 객체를 만들면 되지 않는가?

    결론적으로 말하면, 하나의 오브젝트만을 만들어 서버의 과부하를 막기 위함이다.

    스프링의 싱글톤 레지스트리 덕분에 싱글톤 방식으로 사용될 애플리케이션 클래스라도 public 생성자를 가질 수 있다. 싱글톤으로 사용돼야 하는 환경이 아니라면 간단히 오브젝트를 생성해서 사용할 수 있다. 따라서 테스트 환경에서 자유롭게 오브젝트를 만들 수 있고, 테스트를 위한 목 오브젝트로 대체하는 것도 간단하다.

    가장 중요한 것은 싱글톤 패턴과 달리 스프링이 지지하는 객체지향적인 설계 방식과 원칙, 디자인 패턴(싱글톤패턴은제외) 등을 적용하는 데 아무런 제약이 없다는 점이다. 스프링은 IoC 컨테이너일 뿐만 아니라, 고전적인 싱글톤 패턴을 대신해서 싱글톤을 만들고 관리해주는 싱글톤 레지스트리라는 점을 기억해두자. 스프링이 빈을 싱글톤으로 만드는 것은 결국 오브젝트의 생성 방법을 제어하는 IoC 컨테이너로서의 역할이다.

    -토비의 스트링3.0 107~110p

  • @Component: 클래스 레벨에서 선언함으로써 스프링이 런타임시에 컴포넌트스캔을 하여 자동으로 빈을 찾고 등록하는 애노테이션이다. 개발자가 직접 컨트롤이 가능한 Class들의 경우엔 @Component를 사용한다.

    @Component
    public class Utility {
       // ...
    }

https://galid1.tistory.com/494

https://youngjinmo.github.io/2021/06/bean-component/


의존성 주입(DI, Dependency Injection)

Spring Framwork의 IoC에서 관리하고 있는 Bean들 중에서 필요한 것을 객체에 주입하는 것

@Autowired를 통한 DI

  • 생성자를 통해 Bean에 의존성 주입(Recommended)
    @Service
    public class OrderService {
      ProductRepository productRepository;
        
      @Autowired
      public OrderService(ProductRepository productRepository) { 
        // 생성자가 하나뿐이면 @Autowired 생략 가능
        this.productRepository = productRepository;
      }
    }
    Spring Framework Reference에서 권장하는 방법은 생성자를 통해 Bean의 의존성을 주입하는 방법이다. 왜냐하면 필수적으로 사용해야하는 의존성 없이는 인스턴스를 만들지 못하도록 강제할 수 있기 때문이다. 💡 생성자 방식에서 생성자가 단 하나뿐이면 `@Autowired`가 생략 가능하다고 했는데, 이를 [lombok](https://projectlombok.org/)과 함께 사용해서 편하게 주입하는 방법도 있다. lombok에서 `@RequiredArgsConstructor`Annotation을 붙이면 필수 member(final로 선언된)를 받는 생성자가 자동으로 만들어지고, 이 클래스가 Component scan의 대상인 클래스라면 단 하나의 생성자만 있기 때문에 `@Autowired`가 생략 가능해진다.
  • Setter을 통해 Bean에 의존성 주입(NOT recommended)
    @Service
    public class OrderService {
      ProductRepository productRepository;
    
      @Autowired
      public void setProductRepository(ProductRepository productRepository) {
        this.productRepository = productRepository;
      }
    }
    단점 : set methodpublic으로 열어둬야 하니 변경 가능한 위험
  • Field을 통해 Bean에 의존성 주입(NOT recommended)
    @Service
    public class OrderService {
      @Autowired
      ProductRepository productRepository;
    }
    Spring framework 없이는 productRepository가 초기화 되지 않는 문제점이 있다. 이 때문에 Test 프레임워크 등에서는 NullpointException뜨는 등의 문제가 발생한다. 깔끔해 보이지만 IntelliJ도 워닝을 띄워준다.
  • 일반 Method에 의존성 주입
    @Service
    public class OrderService {
      @Autowired
      ProductRepository productRepository;
    }

https://ch4njun.tistory.com/219

https://gayuna.github.io/spring/spring-bean/

profile
쾌락코딩

0개의 댓글