Drill Instuctor 가 아니다.
이전시간에 학습했던 Dependency Injection이다.
이를 이해하기 위해선 스프링 컨테이너, bean을 이해해야 한다.
출처
Spring IoC 컨테이너가 관리하는 자바 객체를 빈(Bean)이라고 부른다.
스프링은 처음 어플리케이션을 작동하면, 컨테이너에 Bean이라는것들을 올린다. 그리고 이 빈에 담겨있는 정보들을 이용하여 필요한것을 불러서 사용하는 방식이다.
Bean을 컨테이너에 등록하는 방법에는 두가지 방법이 있다.
package com.example.hellospring.controller;
import com.example.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라는 파일이 있다. 이 파일은 컨트롤러 파일인데, 잘 보면 Controller라는 어노테이션이 붙어있는것을 알 수있다.
이 컨트롤러는 MemberService를 정의하고 있는데 이 MemberService는 Constructor를 통해 외부에서 memberservice를 받아서 수행한다. (받는 방법 역시 3가지 정도 있는데 추후 설명하겠다.)
그리고 이 Constructor 위에는 @AutoWired라는 Annotation이 붙어있다.
이처럼 Annotation을 붙여놓고, Spring이 실행될 때 알아서 스캔 후 빈 등록을 하도록 하는것이 바로 Annotation 방식이다.
@Component Annotation이 등록외어 있는 Spring에서는
@Repository, @Service, @Controller, @AutoWired등의 어노테이션을 사용한다.
컨트롤의 경우, 이 방법 말고는 Bean에 올릴 방법이 없다. 따라서 무조건 @Control, @AutoWired를 사용해야만 한다.
스프링은 기본적으로 싱글톤(하나만 등록해서 사용)을 한다. 따라서 두 서비스가 Repositroy에 접근하더라도 메모리를 절약할 수 있다.
package com.example.hellospring;
import com.example.hellospring.repository.MemberRepository;
import com.example.hellospring.repository.MemoryMemberRepository;
import com.example.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();
}
}
Application과 같은 level에 Springconfig 파일을 만들고 그 안에 @Bean을 붙인 코드들을 생성한다.
위의 예제에서는 서비스와 레포지토리의 Bean을 만들었다.
package com.example.hellospring.controller;
import com.example.hellospring.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class MemberController {
@Autowired private final MemberService memberService;
이렇게 바로 Autowird 해주는 방식이다. 절대 권장하지 않는다
@Controller
public class MemberController {
private final MemberService memberService;
@Autowired
public void setMemberService (MemberService memberService) {
this.memberService = memberService;
}
다만 이러한 문제점은 실무에서 한번 setting을 하고나면 바꿀일이 없는것들도 실수로 바꾸게 될 수도 있다는 문제점이 있다.
@Bean
public MemberService memberService() {
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
가장 많이 쓰이는 방법이다
이는 나중에 아무런 코드변경없이 리포지토리를 변경할 때 자바코드 방식을 사용하면 좋기때문에 이렇게 사용한다.
실무에서는 정형화된 컨트롤러, 서비스, 리포지토리 코드는 컴포넌트 스캔(annotation)을 이용하지만, 상황에 따라 구현 클래스가 변하는 경우나 정형화되지 않은 경우라면 spring bean을 이용한다.