우리가 기존에 만들었던 회원관리 예제에서
이 모든것을 화면에 연결해서 보여주고 싶어요!
회원가입하고, 회원가입된 결과를 화면에 보여주려면 어떻게 해야 할까? 그럼 당연히 controller를 만들어야 겠지!
controller는 service를 통하여 회원가입하고, 멤버를 조회할 수 있어야 한다.
이러한 관계를 서로 의존관계에 있다고 합니다.
그 작업을 스프링스럽게 합시다. 자, 이제 회원 컨트롤러가 회원 서비스와 회원 리포지토리를 사용할 수 있게끔 의존관계를 만들어보도록 하자!
이렇게 controller 폴더 안에 member를 컨트롤 할 수 있는 java파일을 하나 생성합니다.
package Inflearn_spring.studyspring.controller;
import org.springframework.stereotype.Controller;
@Controller
public class MemberController {
}
이렇게 생성을 해두기만 해도 스프링 컨테이너에 이 controller 객체를 만들어서 컨테이너에 넣어둔다.
컨트롤러 안에다가 MemberServic
와 관련된 객체를 만들고 싶을 때
private final MemberService memberService = new MemberService();
이렇게 만들면 안된다. 왜냐하면, 다른 친구들도 이 친구를 가져다 써야할텐데 그때마다 독립적으로 new
라고 만들어주면 안되니까?
그러니까, Spring Container에 하나만 등록하고 그것을 계속 이용하면 되잖아?
@Autowired를 추가해주자!!
생성자에 @Autowired가 있으면 스프링이 연관된 객체를 스프링 컨테이너에서 찾아서 넣어준다. 이렇게 객체 의존관계를 외부에서 넣어주는것을 DI (Dependency Injection), 의존성 주입이라한다.
constructor
을 이용하여서 임의로 데이터를 연결해준 내용을 다시 한번 복습해보자.
@Controller
public class MemberController {
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
}
이렇게 생겼다. 이제 잘 실행하나 했더니..오류가 발생한다.
오잉, Memberservice
가 컨테이너에 등록이 되어 있지 않나보다.
Memberservice
에 가보면 얘는 순수한 자바 클래스이고, 컨테이너가 이것을 알아차릴 수 없는 것!
(helloController는 스프링이 제공하는 컨트롤러여서 스프링 빈으로 자동 등록된거. - @Controller는 자동 등록됨! 서비스랑 컨트롤러 연결해주는 그런거는 직접 해주어야 한다는 점!)
그러니까 Service 파일에 가서 아래 코드를 추가해주자.
@Service
public class MemberService {
private final MemberRepository memberRepository;
@Autowired
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
...
@Service
를 통하여,스프링이 스프링 컨테이너에 member serivce를 스프링 빈으로 등록을 해준다. 리포지토리도 마찬가지이다.
@Repository
public class MemoryMemberRepository implements MemberRepository {
private static Map<Long, Member> store = new HashMap<>();
private static long sequence = 0L;
...
스프링이 컨트롤러, 리포지토리, 서비스를 좍 가져올 수 있도록 한 것.
이제 컨트롤러와 서비스를 연결시켜주어야 하니까, @Autowired
를 사용하는 것이다. @Autowired
를 사용하면, 해당되는 객체가 생성되는 시점에 스프링 컨테이너에서 해당 스프링 빈을 찾아서 주입합니다.
자, 이제 MemberController
가 생성이 될 때, Spring bean 안에 들어있는 Memberservice
객체를 가져와서 주입을 해준다. 이것을 바로 dependency injection.이라고 하는 것이다. 밖에서 넣어준 것!!
이 사진을 보면 memberSerivice
도 memberRepository
가 필요하니까 아래와 같이 @AutoWired
를 넣어서 레포지토리를 주입시켜주어야 한다.
@Service
public class MemberService {
private final MemberRepository memberRepository;
@Autowired
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
자 그럼 얘네 이제 연결이 잘 되었네~ 실행시켜보자.
이제 문제 없이 컴파일이 완성되었다.
우리가 위에서 수행한 방법은 바로 컴포넌트 스캔과 자동 의존관계설정이다.
사실 우리가 위에서는 @Service
, @Repository
와 같이 작성을 했지만, 그것을 따라서 원본 파일로 들어가 보면 이러한 현상이 일어난다.
컴포넌트 안에 Service
가 존재하네! 그래서 원래 이름을 컴포넌트 스캔이라고 하는 것이다. 컴포넌트와 관련한 에노테이션이 있으면 컨테이너에 등록을 하기 때문에.
@Component
에노테이션이 있으면 스프링 빈으로 자동 등록된다.@Controller
컨트롤러가 스프링 빈으로 자동 등록된 이유도 컴포넌트 스캔 때문이다.@Controller
, @Service
, @Repository
도 @Component를 포함하기 때문에 자동으로 스프링 빈으로 등록된다. 아쉽게도 그건 불가능하다.
여기 들어가서 확인을 해보면... 스캔해서 실행시키는 패키지는 자신의 하위 패키지만 스캔하여 실행하기 때문에 아무거나 막 만든다고 해서 얘가 다 해주지를 않아요~
스프링은 스프링 컨테이너에 스프링 빈을 등록할 때, 기본으로 싱글톤으로 등록한다. 유일하게 하나만 등록해서 공유하기 때문에, 같은 스프링 빈은 같은 인스턴스로 인식하고 사용해야 한다.
일단 앞서 우리가 작성했던 애노테이션을 다 지워야한다.
그리고 파일을 하나 생성해서 SpringConfig
라고 이름짓습니다.
아래 코드에서 직접 Bean을 하나하나 등록해줍니다.
@Configuration
public class SpringConfig {
@Bean
public MemberService memberService() {
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
여기서 주의해야 할 점은 MemberService
는 MemberRepository
의 Bean이 필요합니다. 그렇기 때문에 생성한 내용을 저기에 꼭 연결을 해 주어야 해~
컨트롤러는 어짜피 Spring에서 관리하는 것이기 때문에 내가 뭐 어떻게 더 할 게 없습니다요. 여기까지 하면 아래 그림이 완성된다! :)
타란~ 얘도 문제없이 빌드가 잘 되어서 포트 8080 열렸따!