혼자 공부한 내용이므로 틀린 내용이 있을 수 있습니다.
만약 레포지토리(저장소)를 바꾸는 상황이 있다면 Repository 인터페이스를 하나 생성해서 해당 인터페이스를 구현하는 새로운 클래스를 만들어 교체하면 된다. 하지만 이러한 방식은 Repository 를 사용하는 Serivce 에서 여러개를 사용한다면 모든 코드를 바꿔야 하기에 비효율적이다.
스프링 컨테이너를 사용하면 스프링빈에 등록된 것들 중에서 대신 객체를 만들어주고 알아서 Repository를 결정해서 주입시켜준다.
만약 레포지토리의 종류가 두개 MemoryRepository, MysqlRepository 가 존재한다면, 아래와 같이 작성하게 된다. 근데 두개 이상의 레포지토리가 존재한다면 직접 사용할 레포지토리는 @Primary 어노테이션을 붙여서 사용하게 된다. 예시로 MysqlRepository를 사용하도록 한다면 아래와 같다.
@Primary // 해당 스프링빈을 사용할 거라는 의미
@Repository // Repository 어노테이션을 통해 스프링빈 등록 -> 자동으로 객체 생성 -> Serivce에서 주입만 시켜주면 됨
public class BookMysqlRepository implements BookRepository {
@Override
public void saveBook() {
System.out.println("BookMysqlRepository.saveBook");
}
}
@Repository
public class BookMemoryRepository implements BookRepository {
private final List<Book> books = new ArrayList<Book>();
@Override
public void saveBook() {
System.out.println("BookMemoryRepository.saveBook");
}
}
@Service
public class BookService {
private final BookRepository bookRepository;
public BookService(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
public void saveBook() {
bookRepository.saveBook();
}
}
그럼 결과적으로 MysqlRepository 저장소를 사용하게 된다. Service 코드에서 볼 수 있듯이 Repository 에 대한 객체를 만들지 않고 '주입'만 시켜주고 있다. (스프링빈을 사용했기 때문에)
@RestController
public class UserController {
private final UserService userService;
@Autowired // 스프링 버전이 올라가며 안붙여도 상관 없음
public UserController(UserService userService) {
this.userService = userService;
}
위와 같이 생성자를 통해 주입한다.
public class UserRepository {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Autowird
private jdbcTemplate jdbcTemplate;
메서드에 @Bean 어노테이션을 붙이면 해당 메서드에서 반환 되는 객체가 스프링 빈에 등록된다.
@Configuration
public calss UserConfiguration {
@Bean
public UserRepository userRepository(JdbcTemplate jdbcTemplate) {
reutrun new UserRepository(jdbcTemplate);
}
}
이렇게 해도 스프링빈에 등록될 수 있지만 이러한 방법은 외부 라이브러리를 가져올 경우 사용한다.