SPRING Framework

Ga0·2023년 4월 8일
1

SPRING

목록 보기
1/14
post-thumbnail

" SPRING을 쓰면 JSP로 웹 개발했을 때보단 코드 치는 양이 적어 편하긴한데, 머리속으로 SPRING 개념들이 정리가 되지않아 뒤죽박죽 혼란스러워서 고민 끝에 POST를 하기로 결심했다. (많이 부족하겠지만, 내가 이해한 기반으로 정리할 예정이다.) "

  • SPRING을 정리하기 전에 FrameworkLibrary에 대해 간단히 정리하려한다. (그에 대한 내용은 아래와 같다.)

프레임워크

  • 원하는 기능 구현에 집중하여 개발할 수 있도록 일정한 형태와 필요한 기능을 갖추고 있는 골격, 뼈대를 의미한다.
  • 그림으로 표현한다면, 이렇게 표현할 수 있을 것 같다.

라이브러리

  • 소프트웨어를 개발할 때 컴퓨터 프로그램이 사용하는 비휘발성 자원의 모임. 즉 특정 기능을 모아둔 코드, 함수들의 집합이며 코드 작성 시 활용 가능한 도구들을 의미합니다. (필요할때 찾아서 추가하는 방식)

Spring Framework이란?

  • Java 기반의 오픈소스 Back-end 프레임워크으로 그냥 SPRING이라고 부른다.

  • 간단하게 말하면 JAVA/Kotlin 기반의 프로그램을 쉽고 빠르게 만들 수 있도록 도와주는 도구(프레임워크)라고 말할 수 있다.

  • SPRING은 의존성 주입(DI; Dependency Injection)과 제어역전(IOC; Inversion of Control), 관점 지향 프로그래밍(AOP)이 가장 중요한 요소인데, 이 각각의 요소들은 느슨한 결합(Loose Coupling)을 달성할 수 있게 한다.

  • 느슨한 결합으로 개발한 프로그램은 단위 테스트를 하기 용이하다.

느슨한 결합에 관한 POST는 강한결합 vs. 느슨한 결합에서 내 나름대로 정리해보았다.

의존성 주입(DI; Dependency Injection)

  • 위의 그림을 보면 방법1의 경우 A객체가 직접 new 연산자를 통해 B,C객체를 만드는 것을 볼 수있다.
  • 두번째 방법은 외부에서 생성된 객체(B, C)를 가져와 사용하는 방법인데 이를 의존성 주입이라고 한다.
  • '외부'에서 클라이언트에게 서비스를 제공(주입)하는 것으로, 다시말하면 객체가 필요로 하는 어떠한 것을 외부에서 전달해주는 것이다.
  • Spring이 다른 프레임워크와 차별화되어 제공하는 의존 관계 주입 기능으로, 객체(Spring에서는 객체를 Bean이라고 부른다)를 직접 생성하는 것이 아니라 외부에서 생성하고 주입해준다.
  • 의존성 주입(DI)를 통해 모듈간의 결합도가 낮아지고 유연성이 높아진다.
  • 스프링 프레임워크에서 의존성을 주입하는 방법 3가지가 존재한다.
  1. 생성자 주입(Constructor Injection)
@Controller 
public class MemberController{
   private memberService memberService;

   @Autowiredpublic Controller(MemberService memberService){
     this.memberService = memberService; 
   }
}
  1. 필드 주입(Field Injection)
@Controller
public class MemberController{
  @Autowired 
  private MemberService memberService;
}
  1. 수정자 주입(Setter Injection)
@Controller 
public class MemberController{
   private MemberService memberService;

   @Autowiredpublic setService(MemberService memberServicememberService){
     this.memberService = memberService; 
   }
}

-> 스프링은 생성자 주입(Constructor Injection) 방식을 권장한다.

제어역전(IoC; Inversion of Control)

  • 개발자가 직접 의존성을 제어하던 것을 매개체에게 일임(제어권을 빼앗기거나, 주거나)하게 되어 제어의 주체가 개발자가 되는게 아니게 되는 것을 제어역전이라고 한다.
  • IoC Container : 개발자에게 일임받은 제어권을 사용하여 의존성을 관리하고 인스턴스를 생성해 주입해주고, 메모리를 해제해주는 역할까지 해준다.
    - Ioc Container은 framwork가 이 역할을 담당하는데, Spring Framwork에 IoC Controller를 포함하고 있다.

  • 다시말해 의존성 주입은 IoC Container이라는 매개체를 두고 필요한 모든 모듈들을 등록해둔다.
    -> 그리고 그 모듈들을 사용하고자 할때, 직접 생성해서 사용하는 것이 아니라, 필요할 때 IoC Container가 의존성이 있는 모듈들을 주입해주는 방식이다.
  • 이 과정에서, 모듈의 생성과 해제, 주입과 같은 일련의 제어들을 IoC Container를 포함하는 FrameWork에게 주면서 제어의 역전이 일어나게 되는 것!

스프링 순서

  1. 객체 생성
  2. 의존성 객체 주입(스스로 만드는 것이 아니라 제어권을 스프링에게 위임하여 스프링을 만들어놓은 객체를 주입한다.)
  3. 의존성 객체 메소드 호출

IoC 코드 예시

package ezenweb.web.domain.todo;

import org.springframework.data.domain.Page;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

//1.객체 생성
@Repository
public interface TodoEntityRepository extends JpaRepository<TodoEntity, Integer>{

}
package ezenweb.web.service;

import ezenweb.web.domain.todo.PageDto;
import ezenweb.web.domain.todo.TodoDto;
import ezenweb.web.domain.todo.TodoEntity;
import ezenweb.web.domain.todo.TodoEntityRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Service //제어 역전(IoC) => 스프링이 관리해줌
@Slf4j
public class TodoService {
    @Autowired
    TodoEntityRepository todoEntityRepository; //2. 의존성 객체 주입(DI)


    //할일 출력
    @Transactional
    public PageDto getTodo(int page){
        List<TodoDto> todoDtoList = new ArrayList<>();

        Pageable pageable = PageRequest.of(page-1, 5, Sort.by(Sort.Direction.DESC, "id"));

        Page<TodoEntity> entity = todoEntityRepository.findAll(pageable); //의존성 객체 메소드 호출

        entity.forEach((e) -> {
            todoDtoList.add(e.toDto());
        });

        return PageDto.builder()
                .totalCount(entity.getTotalElements())
                .totalPage(entity.getTotalPages())
                .todoList(todoDtoList)
                .page(page)
                .build();
    }

  • 의존성 객체의 메소드인 findAll()을 호출함으로 해당 데이터를 모두 가져오는 이 과정이 IoC 코드 예시라고 볼 수 있다.

이러한 구조의 장점!

  • 의존성 감소

    • 사용하는 클래스에서 직접 생성하는 것이 아니라 IoC Container을 통해서 사용하기 때문이다.
    • 변화에 강함
    • 재사용성이 좋아짐
    • 유지보수 용이
  • 코드량 감소

    • 모듈의 생성과 삭제 등을 직접할 필요가 없기 때문에, 코드량이 감소한다. => 작업 속도도 빨라진다.
  • 테스트 용이

    • 외부에서 의존성을 직접 주입받기 때문에 테스트를 하기에도 용이, 자신이 원하는 객체 상태를 직접 세팅하여 주입할 수 있기 때문에 내가 원하는 테스트 코드를 작성하기에 더 편리하다

객체 지향 프로그래밍(OOP)

  • OOP는 Object Oriented Programming의 약자로 모든 데이터를 현실에 빗대어 객체로 다루는 프로그래밍 기법
  1. 캡슐화
    • 데이터와 함수를 하나로 묶어 데이터의 세부 내용을 은닉할 수 있게 되고, 데이터 변경으로 인한 에러가 줄고, 객체간의 데이터를 알 필요가 없기 때문에 코드가 단순해진다.
    • 객체와 함수의 재사용이 쉬워짐.
  2. 정보은닉
    • private로 선언한 데이터는 자기 자신을 통해서만 접근이 가능(setter, getter)
    • 각 객체간의 수정으로 인한 다른 객체에게 미치는 영향을 최소화
    • 외부 객체의 직접 접근을 막아 프로그램 확장시 오류를 최소화
  3. 추상화
    • 불필요한 부분은 생략하고 중요한 것에만 초점을 맞춰 모델로 만듬
    • 복잡한 모델을 중요한 것만 추려 추상화함으로써 시스템 구조를 시각적으로 표현가능
    • 완전한 시스템이 아니더라도 개략적인 모델을 만들어 테스트할 수 있음
  4. 상속성
    • 부모클래스에 정의된 모든 것을 자식 클래스가 물려받는다.
    • 재정의 할 필요(ex. 필드, 메서드 등등)가 없어 코드 작성이 간결해진다.
    • 상속으로 인한 최소한의 규칙을 통해 프로그램 확장시 오류를 최소화
    • 자식클래스에서 새로운 함수를 추가하거나 부모클래스의 함수를 재정이(Overriding)해 사용할 수 있다.
    • 클래스의 재사용이 쉽다.
  5. 다형성
    • 하나의 클래스에서 같은 이름의 함수를 여러개 가질 수 있다(Overloading).
    • 어떤 input 매개변수를 사용해 호출하는지에 따라 다른 함수가 호출됨(ex. 여러 생성자들(?))
    • 비슷한 기능을 하는 함수를 만들때 불필요하게 너무 많은 함수명을 만들게 되면 코드 가독성이 떨어짐

관점 지향 프로그래밍(AOP)

  • AOP는 Aspect Oriented Programming의 약자로 OOP를 좀 더 발전시키기위한 개념이다.

  • 어떤 로직을 기준으로 핵심적인 관점, 부가적인 관점으로 나누어서 보고 그 관점을 기준으로 각각 모듈화하여 재사용할 수 있도록 지원하는 것을 의미한다.

  • 핵심적인 관점 : 우리가 적용하고자 하는 핵심 비즈니스 로직

  • 부가적인 관점 : 핵심 비즈니스 로직을 실행하기 위해 행해지는 데이터베이스 연결, 로깅(기록), 파일 입출력 등과 같은 부가적인 것.

  • 위의 사진을 보면 계좌등록, 대출승인, 입출금은 OOP로 프로그래밍이된 것이고, 각 OOP는 기능 작동을 위해 로깅, 보안, 트랜잭션을 하는 코드가 구현(공통된 기능)되어 있다.

  • 이러한 공통 부분 코드를 각각의 OOP 소스코드에서 제거해서 외부를 빼내어 하나의 공통 모듈로 만들 수 있다.
    => 이를 OOP >> AOP(발전된 OOP)기법이라고 한다.

  • 예시로 다시 정리해보면,

  • 핵심관심 : (각 서비스의 핵심! 비즈니스 로직)계좌 등록, 대출 승인, 입출금

  • 횡단관심 : (공통모듈)로깅, 보안, 트랜잭션 등등

AOP의 핵심! 공통모듈을 분리시켜 해당 소스코드가 외부의 다른 클래스에서 존재하는 것

AOP의 장점

  • 각 비지니스 로직마다의 중복된 코드를 줄여 코드량을 줄일 수 있다.
  • 각 비즈니스 로직을 구현하는 개발자는 자기 자신의 비즈니스 코드에만 집중할 수 있어, 코드는 더욱 간결해지고, 유지보수가 쉬워진다.
  • 재활용성/재사용성이 더욱 높아진다.

AOP의 구성 요소

  • aspect

    • 공통 기능(부가 기능)을 가지는 대상
    • advice(what)와 pointcut(when)으로 구성
  • Advice

    • 공통 기능(부가 기능)을 담은 구현체
    • 메서드 실행 시점, 생성자 호출 시점, 필드 값 접근 시점
  • JointPoint

    • Advice을 삽입할 시점(when)을 의미
    • 시점 : 함수를 실행 전(Before), 실행 후(After), 반환 후(AfterReturning), 예외 발생 시(AfterThrowing), 실행 전과 후(Around)으로 나뉨
  • PointCut

    • advice가 적용될 타켓 지정 기능
    • JoinPoing의 부분 집합으로서 실제 Advice가 적용되는 joinpoint를 나타냄.
    • 어떤 클래스의 어떤 함수가 삽입될 건지 위치를 나타냄!
  • Aspect

    • JoinPoint(when)와 PointCut(where)를 합친 것
    • 여러 객체에 공통으로 적용되는 기능으로, 일정한 패턴을 가지는 클래스에 Advice를 적용하도록 지원할 수 있는 것
  • Proxy

    • 횡단 관심이 핵심 관심에서 직접 실행되지 않고 대리인(Proxy)을 생성해 실행
  • Weaving

    • Aspect(when + where) + Advice(what), Weaving을 통해 지정된 객체를 새 Proxy 객체로 생성한다.
    • 이 과정을 도와주는 것이 AOP 툴이 하는 역할이다.
  • Target

    • 실질적인 비지니스 로직을 구현하는 코드(핵심관점)
      - Advice 받을 대상
    • 객체로 비즈니스 로직을 수행하는 클래수일 수도 있지만, Proxy객체가 될수도 있음.

참고 자료


  • 첫 SPRING POST를 마치는데,,, 생각보다 너무 오래 걸렸고, 이렇게까지 많은 양을 한꺼번에 올릴 생각이 없었는데, 하다보니 새로운게 또 새로운게...🤯

0개의 댓글