Spring Boot 기초 타파

이완희·2023년 8월 1일
0

Spring vs Spring Boot

둘 다 Spring Framework입니다.

Spring Boot가 Spring에 비해 여러가지 장점이 있습니다.

  1. Dependency등록이 쉽다. maven이나 gradle를 사용하면 코드 몇줄로 dependecy를 추가할수 있다.

    코드 자체가 확실히 짧아지고 버전도 권장 버전으로 설정 가능하다. configuration에서도 마찬가지이다.

  2. 내장서버를 제공한다. 외장서버를 불러들이지 않으니 구동시간도 훨씬 짧아진다. 또한 배포를 위해 War파일을 통해 Tomcat에 배포할 필요도 없다. ex) java -jar $REPOSITORY/&JAR_NAME

  3. Security, JPA에 대한 사용도 훨씬 쉽다.

개발에만 쉽게 집중할수 있게 해주는데 어지간하면 Spring Boot쓰자요.

IoC

개발자가 객체를 생성하고 관리하는 것이 아니라 프레임워크에게 생성 역할을 부여한다.

public class User () {
	String nickName;
    String password;
}

public static void main(String[] args) {
		User user = new User();
}

객체 생성의 예시입니다. 클라이언트가 new로 직접 객체를 생성합니다. 생성 뿐만 아니라 초기화, 소멸, 메소드 호출등의 작업을 객체의 생명주기를 관리한다고 합니다. 하지만 프레임워크는 어떨까요? Service, Repository를 사용할 때 new 연산자를 이용하여 객체를 생성하진 않았습니다. @Autowired, @ComponentScan등을 통해 호출만 했습니다. 생명주기를 프레임워크에게 위임한겁니다. 개발자가 아닌 프레임워크가 생명주기를 관리하는 것, 이를 제어의 역전이라 합니다. 참고로 이러한 객체(오브젝트)를 스프링에서는 Bean이라 합니다.

제어의 역전이 무엇인지는 알겠는데 어떤 장점이 있길래 쓰는 걸까요?

  • 프로그램의 진행 흐름과 구체적인 구현을 분리시킬 수 있다.
  • 개발자는 비지니스 로직에만 집중한다.
  • 구현체 사이의 변경이 용이하다.
  • 객체 간 의존성이 낮아진다.

→ 높응낮결을 하게해준다.

이를 통해 라이브러리와 프레임워크의 가장 큰 차이점을 알수 있습니다. 라이브러리는 개발자가 직접 호출하여 객체의 생명주기를 관리하지만 프레임워크는 반대입니다.

DI(Dependency Injection)

IoC와 DI는 동일한 개념이 아닙니다. DI는 IoC를 구현하기 위해 사용하는 디자인 패턴입니다.

예시를 통해 알아보겠습니다.

  • DI를 사용하지 않음
public class OrderService {
    private DBConnection dbConnection;

    public OrderService() {
        dbConnection = new DBConnection(); // 직접 생성
    }

    public void processOrder(Order order) {
        // 주문 처리 로직
        dbConnection.save(order); // DBConnection에 의존하여 저장
    }
}

OrderService는 DBConnection클래스에 의존하고 있습니다. 의존성이 높아서 DBConnection의 변경이 발생하면 수정이 번거롭습니다.

  • DI를 사용함
public class OrderService {
    private DBConnection dbConnection;

    public OrderService(DBConnection dbConnection) {
        this.dbConnection = dbConnection; // 주입 받음
    }

    public void processOrder(Order order) {
        // 주문 처리 로직
        dbConnection.save(order); // 주입받은 DBConnection 사용
    }
}

마찬가지로 OrderService는 DBConnection를 의존하고 있지만 어떤 종류의 DBConnection를 주입받던지간에 OrderService는 상관없습니다.

DI는 쉽게 말해 객체 간의 의존관계를 외부(스프링 컨테이너)에서 결정하고 주입하는 것입니다.

의존성 주입방법엔 총 3가지가 있습니다. 생성자 주입, Setter 주입, 인터페이스 주입.

인터페이스 주입은 걍 패스할게요. Setter주입은 지금은 권장하지 않고 생성자 주입을 사용하라고 합니다.

왜일까요? 객체가 생성되는 시점에 Bean을 주입하기 때문에 NPE를 방지할 수 있습니다. 또한 final로 선언하므로 불변성을 활용할 수도 있습니다. Setter 주입시 발생할 수 있는 순환 참조 오류도 사전에 방지할 수 있습니다.

Spring 동작 원리

그림을 통해 쉽게 이해해봐요.

  1. 사용자의 요청을 Dispatcher Servlet이 받습니다. HandlerMapping에게 Request할 Controller찾으라고 시킵니다.
  2. Handler Mapping이 검색을 요청받은 Controller을 찾아 Dispatch Servlet에게 반환합니다.
  3. Handler Mapping이 찾은 컨트롤러를 직접 실행합니다. Handler Interceptor은 Controller가 매핑되기전 앞단에 부가적인 로직을 끼워넣습니다. 쿠킹, 세션, 로그인 등 권한 생성하는 JWT가 그 예시네요.
  4. Controller는 Request를 매핑하고 Service를 호출합니다.
  5. Service를 포함하여 Business Logic을 수행합니다.
  6. Controller에서 리턴한 ModelAndView 객체를 View Resolver은 Dispatcher Servlet에게 넘겨받 습니다.
  7. View Resolver는 Controller의 실행결과를 보여줄 View를 검색합니다.
  8. View는 ModelAndView 객체를 Dispatcher Servlet에게 송신하고 Dispatcher Servlet은 사용자에게 Response를 주고 종료합니다.

막말로 개발자는 Business Logic박스를 제외하고 어떻게 작동하는지 몰라도 애플리케이션을 구현할 수 있습니다. Request가 오면 알아서 호출해주니까요. 이 전에는 불편해서 어땠는지 몰라 참.

마무리

이전까지는 IoC가 DI와 동일한줄 알았고 어떤 개념인지도 정확하게 몰랐다. 이 글을 작성하면서 개념과 차이점에 대해서도 알게되었고 객체 간의 관계를 느슨하게 하여 코드를 보다 유연하게 짤 수 있게 되었다. 요건사항에 맞게 프로덕트를 만드는 것도 중요하지만 low level를 이해하는것도 중요하다고 생각한다. 카레이서가 자동차의 내부 부품의 역할을 알필요는 없겠지만 동작원리를 알아야 적절한 코너링과 감속/가속 타이밍을 알지 않을까? 이후엔 AOP와 트랜잭션에 대해 알아보겠습니다.

profile
인생을 재밌게, 자유롭게

1개의 댓글

comment-user-thumbnail
2023년 8월 1일

개발자로서 성장하는 데 큰 도움이 된 글이었습니다. 감사합니다.

답글 달기