위 세 개의 역할을 각각 나눌 것이다.
Repository → Service → Controller
jdbcTemplate.update() : 데이터를 바꾸는 쿼리 (INSERT, UPDATE, DELETE)
jdbcTemplate.query() : 데이터를 읽는 쿼리 (SELECT)
UserController와 스프링 컨테이너UserController의 의아한 점static 이 아닌 코드를 사용하려면 인스턴스화가 필요하다.new UserController();UserController 자동 인스턴스화@RestControllerUserController 클래스를 스프링 빈으로 등록시킨다. 💡userController, 타입 - UserController)와 함께 인스턴스화(UserController userController = new UserController();)도 이루어진다.UserController를 인스턴스화 하려면 JdbcTemplate이 필요하다. ctrl + shift + N →build.gradle → dependencies에서 확인 가능JdbcTemplate, DataSource, Environment 등 ...UserController 우리가 설정해준 스프링 빈도 등록된다.UserRepository는 JdbcTemplate을 가져오지 못하는 이유💡
JdbcTemplate을 가져오려면UserRepository가 스프링 빈이어야 하는데UserRepository는 스프링이 아니다.
↪ UserRepository를 스프링 빈으로 등록하면 JdbcTemplate을 가져올 수 있다.
UserController
@RestController
public class UserController {
private final UserService userService = new UserService();
public UserController(JdbcTemplate jdbcTemplate)
{
this.userService = new UserService(jdbcTemplate);
}
}
UserSerivce
public class UserService {
private final UserRepository userRepository;
public UserService(JdbcTemplate jdbcTemplate)
{
userRepository = new UserRepository(jdbcTemplate);
}
}
UserRepository
public class UserRepository {
private final JdbcTemplate jdbcTemplate;
public UserRepository(JdbcTemplate jdbcTemplate)
{
this.jdbcTemplate = jdbcTemplate;
}
}
UserController
@RestController
public class UserController {
private final UserService userService;
public UserController(UserService userService)
{
this.userService = userService;
}
}
UserSerivce
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository)
{
this.userRepository = userRepository;
}
}
UserRepository
@Repository
public class UserRepository {
private final JdbcTemplate jdbcTemplate;
public UserRepository(JdbcTemplate jdbcTemplate)
{
this.jdbcTemplate = jdbcTemplate;
}
}
UserRepository는 JdbcTemplate을 가져오고UserService는 UserRepository를 가져오고UserController는 UserService를 가져온다.BookController → BookService → BookRepository → BookMemoryRepository or BookMySqlRepository
@Repository
@Service
@RestController
private final BookRepository bookRepository = new BookRepository(); 이런 과정을 거치지 않아도 된다.BookService에서 BookMemoryRepository를 사용할지, BookMySqlRepository를 사용할지 선택한다.위와 같은 방식을 제어의 역전이라고 한다.
💡 스프링 컨테이너가 어떤
Repository를 사용할지 대신 결정해주는 방식을 제어의 역전(IoC, Inversion of Control)이라고 한다.
💡 컨테이너가Repository를 선택해BookService에 넣어주는 과정을 의존성 주입 (DI, Dependency Injection)이라고 한다.
@Primary
Repository를 사용할지 결정하도록 Repository에 우선권을 부여한다.@Primary
@Repository
public class BookMemoryRepository implements BookRepository
{
}
@Configuration
@Bean을 사용할 때 함께 사용한다.@Bean
@Configuration
public class UserConfiguration {
@Bean
public UserRepository userRepository(JdbcTemplate jdbcTemplate)
{
return new UserRepository(jdbcTemplate);
}
}
@Service, @Repository@Configuration + @Bean@ComponentController, Service, Repository가 모두 아니고(가장 권장) 생성자를 이용해 주입 받는다.
→ @Autowired 생략 가능
setter & @Autowired 사용
→ 오작동의 원인이 될 수 있음
public class UserController
{
private UserService userService;
@Autowired
public void setUserService(UserService userService)
{
this.userService = userService;
}
}
@Autowired를 적는다.@Autowired
private JdbcTemplate jdbcTemplate;
@Qualifier@Qualifier 를 사용할 수 있다.@Qualifier 끼리 연결된다.UserController → FruitService → AppleService | BananaService | OrnageService
private final FruitService fruitService;
public UserController(@Qualifier("appleService") FruitService fruitService)
{
this.fruitService = fruitService;
}
@RestController
public class UserController {
private final FruitService fruitService;
public UserController(UserService userService, @Qualifier("main") FruitService fruitService)
{
this.fruitService = fruitService;
}
}
-------------------------------------------------------
@Service
@Qualifier("main")
public class BananaService implements FruitService
{
}
@Primary vs @Qualifier@Qualifier가 더 우선이다.Controller 코드를 보다 좋은 코드로 리팩토링한다.