※본 글은 김영한님의 '자바 스프링 완전정복 시리즈' 강의를 바탕으로 작성한 글입니다.
스프링을 단순히 웹 프로그래밍을 도와주는 프레임워크라고 생각할 수도 있지만, 그 본질은 객체 지향 프로그래밍에 있습니다.
앞서 좋은 객체 지향 설계를 위한 5가지 원칙, SOLID를 살펴보았습니다.
객체 지향 설계의 5가지 원칙(SOLID)
이때 단순히 다형성만을 이용해서는 OCP, DIP를 완전히 만족할 수 없다는 내용을 다뤘었습니다.
interface MemberRepository{
public void save(Member meber);
}
class MemoryMemberRepository implements Repository{
public void save(Member member){
// 메모리에 저장
}
}
class DBRepository implements Repository{
public void save(Member member){
// DB에 저장
}
}
MemberRepository의 구현체가 위와 같이 존재할 때,
class MemberService{
// MemberRepository memberRepository = new MemoryMemberRepository();
// 구현체만 갈아끼우기
MemberRepository memberRepository = new DBMemberRepository();
void save(Member member){
repository.save(member);
}
}
MemberService에서 의존하는 구현체를 바꾸는 것만으로 Service가 Memory가 아닌 DB에 저장하도록 변경할 수 있었습니다.
다만 문제는 구현체를 갈아끼우는 것이 클라이언트 클래스의 코드의 수정을 통해 이뤄지기 때문에 완전히 OCP를 만족하지 못한다는 것이였습니다.
추가로 현재 구체 class에 의존하기 때문에 DIP도 만족하지 않습니다.
이 문제를 스프링 프레임워크를 통해 해결할 수 있습니다.
먼저 스프링을 이용한 코드를 보겠습니다.
class MemberService{
MemberRepository memberRepository;
@Autowired
public MemberService(MemberRepository memberRepository){
this.memberRepository = memberRepository;
}
void save(Member member){
repository.save(member);
}
}
스프링을 이용한 MemberSerivce 클래스의 코드는 위와 같습니다.
생성자를 통해 memberRepository를 초기화하고, 생성자에 @Autowired 어노테이션이 추가되어 있습니다.
어디에도 memberRepository의 구현체를 선택하는 코드는 없습니다.
@Autowired 어노테이션을 이용하면, 스프링 프레임워크가 스프링 컨테이너에 등록된 빈 중, 타입에 맞는 빈을 찾아서 꽂아주게 됩니다.
(물론 MemberService의 빈을 스프링을 통해 생성하는 경우입니다. JAVA 코드만으로 객체를 생성했을 때는 해당되지 않습니다.)
그렇다면 우리가 할 일은 스프링 컨테이너에 사용할 빈을 등록하는 것 뿐입니다.
다시 메모리에 저장하도록 MemoryMemberRepository를 사용하는 경우를 가정해보면,
interface MemberRepository{
public void save(Member meber);
}
@Repository // 스프링 컨테이너에 빈 등록
class MemoryMemberRepository implements Repository{
public void save(Member member){
// 메모리에 저장
}
}
class DBRepository implements Repository{
public void save(Member member){
// DB에 저장
}
}
위와 같이 사용할 구현체 위에 @Repository 어노테이션을 추가하면 됩니다.
이렇게 하면,
1. 스프링 컨테이너에 MemoryMemberRepository가 등록
2. @Autowired는 컨테이너에서 MemberRepository에 적합한 빈인 MemoryMemberRepository를 MemberService의 생성자에 전달
의 순서로 진행됩니다.
다시 DB를 이용하도록 바꿔주려면, @Repository의 위치만 변경해주면 됩니다.
즉, 클라이언트의 코드를 수정할 필요가 전혀 없어졌습니다.
단순한 예시이지만, 스프링 프레임워크의 본질은 위와 같이 좋은 객체 지향 설계를 도와준다는 것에 있습니다.