2주가량 스프링으로 기본적인 게시판 만들기를 배운뒤 핵심프로젝트를 진행했습니다. 하지만 스프링부트는 시간관계상 배우지 못했지만 스프링을 더 편하게? 이용할수있다길래 궁금해서 팀원들과 상의후에 쓰기로 결정했는데요
무작정 결과물을 위해 대충 공부하고 프로젝트를 발표했지만 2주라는 짧은 시간이였기때문에 충분한 이해를 하지 못했고, 스프링에는 MyBatis만 배웠기때문에 ORM과 JPA의 개념, 핵심개념들을 충분히 숙지하지 못한채로 프로젝트를 진행해서 스스로 공부해보려고 조금씩 개념정리를 해보려고합니다!
처음 배울때 request, response 부터 시작해서 mvc패턴을 배웠는데 어려웠습니다 왜 어려웠나 생각을 해봤는데 자바에 대한 개념이 부족했던거같습니다. 하지만 스프링부트를 쓰려면 기본적으로 동작원리는 알아야 쓸수있다고 하셨기때문에 최대한 수업을 따라가려고 노력했고 스프링부트를 써본결과 선생님의 말씀이 맞습니다... 그래서 열심히 개념을 익혀보겠습니다!
프레임워크
프레임워크란 틀이라고 생각하면되는데, 이 틀안에는 구현된 기능들이 있기때문에 정해진 틀 안에서 개발하는것이라고 생각하면됩니다!
스프링의 프레임워크에는 여러 특징이있는데 오늘은 IoC에 대해 알아보겠습니다!
스프링은 IoC 컨테이너를 가집니다.
IoC컨테이너란(Inversion of Control) 제어의 역전이라는 의미인데요, 주도권이 스프링에게 있다는 뜻 입니다!
자바에서 Class, Object, Instance가 있습니다
Class는 설계도
Object는 실체화가 가능한 것
Instance는 실체화 된 것
가구를 예로 들어보면 가구는 실체화가 불가능합니다. 가구는 추상적인겁니다!
실체화가 가능한것은 의자, 침대 이런걸 Object라고 부릅니다.
이런 Object들이 세상에 나오는 순간 실체화 되었기때문에 Instance라고 불리게 됩니다!
기존에는 Java에서 개발자가 직접 객체를 생성하기 위해 new 키워드를 사용했습니다. 이는 개발자가 객체의 생성과 초기화를 관리하고, 해당 객체가 필요한 곳에서 직접 생성하여 사용하는 방식입니다. 하지만 IoC 컨테이너를 사용하면 객체의 생성과 관리를 컨테이너가 담당합니다. 개발자는 객체의 생성에 대한 책임을 컨테이너에게 위임하고, 필요한 경우 컨테이너에게 해당 객체를 요청하여 사용합니다.
이때 IoC 컨테이너가 new 키워드를 사용하여 객체를 생성하는 것이 아니라, 미리 정의된 설정 정보나 애노테이션 등을 기반으로 객체를 생성하고 주입합니다.
스프링에서는 다음과 같은 순서로 객체가 만들어지고 실행됩니다.
1. 객체 생성
2. 의존성 객체 주입(개발자가 하는것이 아닌 스프링이 만들어놓은 객체를 주입)
3. 의존성 객체 메소드 호출
IoC의 구현 방식은 여러가지가있지만 자주 쓰이는 DI에 대해 살펴보겠습니다
DI(Dependcy Injection)
Dependency Injection이란, 각 객체 간 의존관계를 스프링 컨테이너가 개발자가 정의한 Bean 등록 정보를 바탕으로 자동으로 주입해주는 기능입니다.
일반적인 다양한 기존 스프링 프로젝트를 보면, Controller에서 Service나 Repository 객체를 사용 시, new 키워드를 통해 컨트롤러에서 객체를 직접 생성하여 사용하지 않고 의존성 주입을 통해 스프링 컨테이너에 생성된 객체를 받아 사용하고 있는 것을 볼 수 있습니다. @Service, @Repository, @Controller 등의 어노테이션이 붙은 클래스들은 스프링 실행 시 스캔을 통해 개발자가 정의한 의존성 정보를 자동으로 bean 설정 정보에 등록을 하게 되어 의존성 주입이 동작하게 합니다.
코드에서 직접적인 연관관계가 발생하지 않아 각 클래스들의 변경이 자유로워 지는데, 이를 느슨한 결합이라고 합니다!
@RestController
@RequiredArgsConstructor
public class PostController {
private final postService postService;
@PostMapping("/posts/new")
public String save(Post post, HttpSession session) throws IOException {
userDTO info = (userDTO) session.getAttribute("info");
post.setUser_id(info.getUser_id());
System.out.println("Controller save 확인");
postService.save(post);
return "/";
}
위 코드는 제가 프로젝트에서 작성한 코드인데요 참고로만 봐주시면될거같습니다! Controller 어노테이션이 존재합니다
private final postService postService; // postService 객체에 대한 의존성 주입(DI)
이 부분도 의존성 주입이라고 보면될거같습니다
// 생성자를 통한 의존성 주입
public PostController(postService postService) {
this.postService = postService;
}
Lombok에서 제공하는 @RequiredArgsConstructor을 사용하면 눈에 보이진 않지만 위 코드처럼 생성자 메소드가 생깁니다. (Lombok은 라이브러리 인데요 DTO작성할때 Getter, Setter등 부분을 자동으로 만들어주는 라이브러리라고 생각하면됩니다)
DI를 통해 의존성을 외부에서 주입받게 되면, 해당 클래스는 자신이 어떤 객체에 의존하는지에 대해 알 필요가 없으며, 대신 외부에서 주입되는 객체를 사용하여 동작합니다. 이렇게 하면 클래스 간의 결합도가 낮아지므로, 한 클래스의 변경이 다른 클래스에 미치는 영향이 최소화되고, 코드의 유지보수 및 확장이 용이해집니다.
실제로 제가 쓸때는 이런 개념을 충분히 이해하지 못하고 무작정 썼지만 개념을 정리하면서 살펴보니 더 공부가 잘 되는거같습니다.