
MVC에서 Controller을 분리할 수 있다고 한 부분이 이것!
Controller의 부담을 나눈 것
가독성, 유연성이 높아진다
협업에도 좋다
이때 Controller / Service는 모두 bean으로 등록되어 ioc에 의해 조작된다.

@PutMapping("/memos/{id}")
public Long updateMemo(@PathVariable Long id, @RequestBody MemoRequestDto requestDto) {
MemoService memoService = new MemoService(jdbcTemplate);
return memoService.updateMemo(id, requestDto);
}

이전에 컨트롤러가 하려던 역할 (DB와 소통하는 역할 제외) 여기서 수행
public MemoResponseDto createMemo(MemoRequestDto requestDto) {
// RequestDto -> Entity
Memo memo = new Memo(requestDto);
// DB 저장
MemoRepository memoRepository = new MemoRepository(jdbcTemplate);
Memo saveMemo = memoRepository.save(memo);
// Entity -> ResponseDto
MemoResponseDto memoResponseDto = new MemoResponseDto(saveMemo);
return memoResponseDto;
}

DB 관리 (연결, 해제, 자원 관리)
DB CRUD 작업을 처리
쿼리 작업 등등
public Memo save(Memo memo) {
// DB 저장
KeyHolder keyHolder = new GeneratedKeyHolder(); // 기본 키를 반환받기 위한 객체
String sql = "INSERT INTO memo (username, contents) VALUES (?, ?)";
jdbcTemplate.update(con -> {
PreparedStatement preparedStatement = con.prepareStatement(sql,
Statement.RETURN_GENERATED_KEYS);
preparedStatement.setString(1, memo.getUsername());
preparedStatement.setString(2, memo.getContents());
return preparedStatement;
},
keyHolder);
// DB Insert 후 받아온 기본키 확인
Long id = keyHolder.getKey().longValue();
memo.setId(id);
return memo;
}
좋은 코드 작성을 위한 Spring의 핵심 기술 중 하나이다.
IoC : 설계 원칙 (구현 시 지켜야 할 룰)
DI : 디자인 패턴 (레시피 같은 순서) / 외부에서 미리 만든 객체를 주입
public class Consumer {
void eat() {
Chicken chicken = new Chicken();
chicken.eat();
}
public static void main(String[] args) {
Consumer consumer = new Consumer();
consumer.eat();
}
}
class Chicken {
public void eat() {
System.out.println("치킨을 먹는다.");
}
}
Consumer가 chicken이 아닌 걸 먹고 싶어하면 어쩌지?? > 수정할 거 많아짐
public class Consumer {
void eat(Food food) {
food.eat();
}
public static void main(String[] args) {
Consumer consumer = new Consumer();
consumer.eat(new Chicken());
consumer.eat(new Pizza());
}
}
interface Food {
void eat();
}
class Chicken implements Food{
@Override
public void eat() {
System.out.println("치킨을 먹는다.");
}
}
class Pizza implements Food{
@Override
public void eat() {
System.out.println("피자를 먹는다.");
}
}
이미 만들어진 메소드를 수정할 필요 없이 사용자의 요청에 응답할 수 있다.
다형성의 원리를 사용하여 구현하면 약한 결합, 약한 의존성 실현 가능
여러 방법을 통해 필요로 하는 객체를 해당 객체에 전달하는 것
Food는 인터페이스이고, Chicken, Pizze는 Food를 구현한 클래스이다.
public class Consumer {
Food food;
void eat() {
this.food.eat();
}
public static void main(String[] args) {
Consumer consumer = new Consumer();
consumer.food = new Chicken();
}
interface Food {
void eat();
}
1) Food 객체 생성 (Consumer에 포함 시킴)
2) Food에 필요한 객체를 주입 받음
public void setFood(Food food) {
this.food = food;
}
Setter을 통해 매개변수로 객체를 주입 받음
public class Consumer {
Food food;
public Consumer(Food food) {
this.food = food;
}
생성자를 사용하여 필요한 객체를 주입받아 사용
외부에서 제어하고, 제어를 받는 (가만히 있는) 객체를 변경한다.
한 개의 객체에서 다른 객체를 생성 (new) / 그 객체가 또 다른 객체를 생성 (new)
파라미터로 받아오면 된다
Class Service1 {
private final Repository1 repitory1;
// repository1 객체 사용
public Service1(Repository1 repository1) {
this.repository1 = new Repository1();
this.repository1 = repository1;
}
}
// 객체 생성
Service1 service1 = new Service1(repository1);

SpringFramework가 필요한 객체를 생성, 관리해준다.
Bean을 모아둔 컨테이너
Spring이 관리하는 객체
등록하려는 클래스 위에 @Component 작성

콩이 달려있으면 Bean으로 등록됨! (귀야워..)
클래스 이름에서 맨 앞글자가 대문자 > 소문자로 변경된 이름으로 저장되어 있다.
사용할 메서드 위에 @Autowired
~ 생성자 선언이 하나일 경우에는 생략 가능하다
~ 콩을 눌러보면 어느 Bean이 주입되는 건지 배울 수 있다
~ 필드 / 생성자 / 메서드 주입 모두 가능하지만, final로 선언된 객체의 경우에는 더더욱 생성자 주입이 더 권장된다.
주입할 필드 위에 @Autowired / 추천되진 않는다
Spring Container에 의해 관리되는 Container만 주입 가능하다
@RequiredArgsConstructor를 클래스 위에 선언한다 (생성자 선언)
@Component
@RequiredArgsConstructor // final로 선언된 멤버 변수를 파라미터로 사용하여 생성자를 자동으로 생성합니다.
public class MemoService {
private final MemoRepository memoRepository;
// public MemoService(MemoRepository memoRepository) {
// this.memoRepository = memoRepository;
// }
...
}
직접 IocConatiner에 접근하여 가져오기
@Component
public class MemoService {
private final MemoRepository memoRepository;
public MemoService(ApplicationContext context) {
// 1.'Bean' 이름으로 가져오기
MemoRepository memoRepository
= (MemoRepository) context.getBean("memoRepository");
// 2.'Bean' 클래스 형식으로 가져오기
// MemoRepository memoRepository = context.getBean(MemoRepository.class);
this.memoRepository = memoRepository;
}
...
}
Controller은 어디에서 호출되는 걸까?
Dispatcher Servlet이 호출하는 거임! 따로 호출하지 않아도 내부적으로 호출한다.
1) DB 테이블 만들기
2) 애플리케이션에서 SQL 작성
3) SQL을 JDBC를 사용해서 직접 실행
4) SQL 결과를 객체로 직접 만들기
SQL 의존적이라 변경에 취약하다.
SQL 수정 > Dto 객체에 값을 주입하는 부분도 변경해야 한다.

객체와 DB의 관계를 직접 매핑하는 도구, SQL 작업을 줄일 수 있다.

자바 ORM 기술에 대한 표준 명세
애플리케이션과 JDBC 사이에서 동작되며, DB 연결 과정을 직접 개발하지 않아도 자동으로 처리해준다.