📂 java/controller/MemberController.java
@Controller
public class MemberController {
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService){
this.memberService=memberService;
}
}
Controller를 생성하여 @Controller 어노테이션과 @Autowired 어노테이션을 사용하였다. 이렇게만 진행을 하게 되면 다음과 같은 그림처럼 일어나게 된다.
그림의 화살표를 @Autowired로 의존관계를 넣어준다고 생각해보면 된다. 그치만 아직 memberService가 Bean으로 등록되어있지 않기 때문에 연결이 되지 않았다.
📂 java/service/MemberService.java
@Service
public class MemberService {
private final MemberRepository memberRepository;
@Autowired
public MemberService(MemberRepository memberRepository){// DI
this.memberRepository = memberRepository;
}
.
.
.
📂 java/repository/MemoryMemberRepository.java
@Repository
public class MemoryMemberRepository implements MemberRepository {
private static Map<Long, Member> store = new HashMap<>();
private static long sequence= 0L;
.
.
.
아래와 같이 각각의 어노테이션들을 추가하였다. Service에서는 @Service Repository에서는 @Repository를 추가하였다.
이번에 추가된 어노테이션은 @Controller, @Repository, @Service를 추가하였다.
@Component
애노테이션이 있으면 스프링 빈으로 자동 등록된다.@Controller
컨트롤러가 스프링 빈으로 자동 등록된 이유도 컴포넌트 스캔이라는 것 때문이다.🏸 @Component
를 포함하는 다음 애노테이션은 스프링 빈으로 자동 등록된다.
@Controller
@Service
@Repository
🏸 그러면 @Autowired?
위 그림에 보면 각각의 스프링 빈이 화살표로 의존관계에 속해있는 것을 볼 수 있는데 @Autowired
를 통하여 스프링 컨테이너에서 해당 스프링 빈을 찾아서 주입시켜주는 역할을 한다.(즉 의존관계 생성)
package com.example.demo_practice;
import com.example.demo_practice.repository.MemberRepository;
import com.example.demo_practice.repository.MemoryMemberRepository;
import com.example.demo_practice.service.MemberService;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;
@Configuration
public class SpringConfig {
@Bean
public MemberService memberService(){
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository(){
return new MemoryMemberRepository();
}
}
이후 실습에서는 자바 코드를 활용하여 Bean을 등록하는 방식으로 가기로 하였다.
@Autowired private MemberService memberService;
이런 유형으로 진행이 되어지는데 이렇게 의존관계를 가지게 되면은 나중에 별도로 변경사항이 일어났을때 변경을 할 수 있는것이 없게 되서 잘 쓰이지 않는다.
@Controller
public class MemberController {
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService){
this.memberService=memberService;
memberService.setMemberRepository()
}
}
------
public class MemberService {
private MemberRepository memberRepository;
public void setMemberRepository(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
와 같이 setter를 주입을 시키는데 문제점이 무엇이냐면 의존관계 주입을 하기위한 메소드인데 public으로 선언이 되야하므로 어쩔 수 없이 모든 사람이 이 메소드에 접근할 수 있어서 좋지 못한 방법이다.
public class SpringConfig {
@Bean
public MemberService memberService(){
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository(){
return new MemoryMemberRepository();
}
}
결국에는 이런 방식으로 생성자에서 주입을 시켜주는 방향으로 가는 것이 제일 좋았다. 그리고 또 장점으로 볼 수 있는 것이 나중에는 MemoryMemberRepository는 다른 Db로 바꿔줘야하기 때문에 이럴 경우 다른 주입방식과 같은 경우에서는 변경을 할 때에는 껄끄러운 부분이 있는 반면 생성자 주입일 경우에는 return new DbMemberRepository();와 같이 이름만 바꿔주면 되는 부분에서 되게 편안하다는 측면이 있다.
김영한 - 스프링 입문 강의