S2U7-U8 [Spring Core] Spring Framework 회고

    반응형

    [Spring Framework 소개]

    💚 프레임워크(Framework)는 애플리케이션을 만들기 위한 틀/구조를 제공한다. 프레임워크가 제공하는 일정한 요소와 규약을 가지고 코드를 작성하기 때문에 개발자는 애플리케이션 핵심 로직을 개발하는 것에 집중할 수 있다. 반면 프레임워크에 대한 학습이 필요하고 자유롭고 유연한 개발이 어렵다.
    라이브러리(Library)는 애플리케이션을 개발할 때 필요한 기능을 미리 구현놓은 집합체로, 코드 내에서 필요한 기능이 있을 때 개발자가 해당 라이브러리를 호출해서 사용한다. (= 애플리케이션 흐름의 주도권을 개발자가 갖는다.) 반면 프레임워크는 애플리케이션 흐름의 주도권을 갖는다. 핵심 개념: IoC(제어의 역전, Invension Of Control)
    Java 기반 프레임워크에는 여러 가지가 있지만 그 중에서도 Spring은 객체 지향 설계 원칙에 맞는 재사용고 확장이 가능한 개발 스킬을 향상시켜주고, 보다 나은 성능과 안정성이 필요한 복잡한 서비스(기업용 엔터프라이즈 시스템)를 제대로 구축 가능하게 한다. JSP, 서블릿을 이용한 애플리케이션에 비해 코드가 눈에 띄게 간결하고, Spring Boot의 경우 복잡한 설정 작업 또한 프레임워크가 처리해주기 때문에 개발자가 핵심 비즈니스 로직에만 집중할 수 있는 환경이 주어진다.


    프레임워크에 대한 개념이나 라이브러리와의 차이점은 잘 알고 있었기 때문에 가볍게 읽고 넘어갈 수 있었고, 자동차를 예시로 든 설명을 보고 한층 더 와닿아서 좋았다. (프레임워크는 차체, 뼈대, 라이브러리는 교체하기 수월한 타이어, 와이퍼 등의 부품) 부끄럽지만 Spring Boot의 가장 큰 특징은 간단한 설정 작업이라는 점을 모르고 있었다!! 그것도 모르고 사용했다니. 이제 와서 생각해보니 Spring Boot가 내장 톰캣을 가지고 있는 것도 같은 줄기인 것 같다.


    [Spring Framework 특징]

    💚 Spring의 특징을 크게 다섯가지로 나누어 간단히 적어보려고 한다.
    1. POJO(Plain Old Java Object)기반 구성: 우선 POJO 프로그래밍은 자바로 작성된 순수한 객체(POJO)를 이용해 코드를 작성하는 것으로, 두 가지 기본 규칙을 갖는다. 첫째는 Java 스펙에 정의된 것 외의 다른 기술이나 규약에 얽매이지 않아야 한다는 것이다. 예를 들어 Java 클래스 코드에서 Struts 프레임워크가 제공하는 Action이라는 클래스를 상속받는 경우 이 규칙을 위반한다. 특정 기술을 상속받아 구현하게 되면 객체지향 설계 기법을 적용하기 어렵고(Java는 다중 상속을 지원하지 않기 때문이다) 요구사항 변경 시 Struts 기술을 사용했던 부분을 일일히 수정/삭제해야 한다. 둘째는 특정 환경에 종속되면 안 된다는 것이다. 예를 들어, Java 코드 내에서 톰캣이 지원하는 API를 사용했을 경우, 톰캣 -> Zetty로 서블릿 컨테이너(환경)를 변경해야 할 경우 코드를 뜯어 고쳐야 할 것이다. 최대한 다른 기술이나 환경에 종속되지 않도록 POJO 프로그래밍 코드를 작성해야 하고 그를 위해 Spring에서 지원하는 아래 기술들을 사용한다.
    2. IoC(Inversion Of Control): 애플리케이션 흐름의 주도권이 뒤바뀐 것. 제어의 역전이다. 서블릿 기반 애플리케이션의 경우 Java 콘솔 애플리케이션과 달리 main()이라는 엔트리 포인트를 갖지 않는다. 그 이유는 클라이언트 요청이 들어올 때마다 서블릿 컨테이너 내의 컨테이너 로직이 서블릿을 직접 실행시켜주기 때문이다. Spring의 경우에는 DI를 통해 IoC 개념을 적용한다.
    3. DI(Dependency Injection): 의존성 주입. 클래스 내부에서 다른 객체를 생성하게 되면 두 클래스 간의 의존 관계가 강하게 형성된다. 생성자 등을 통해 의존하는 객체를 외부에서 주입해주어 결합도를 낮춰준다. 클래스 간의 결합을 약하게 만드는 방법 중 하나는 인터페이스를 사용하는 것이다.(업캐스팅) 객체 간의 결합이 느슨해지면 요구사항 변경에 유연한 코드가 된다. Spring에서의 의존성 주입은 아래에서 정리하려고 한다.
    4. AOP(Aspect Oriented Programming): 관심 지향 프로그래밍. 핵심 비즈니스 로직이 아닌, 애플리케이션 전반에서 공통적으로 사용되는 기능을 부가기능으로 분리하는 것이다. 그렇게 되면 코드가 간결해지고, 보다 객체지향적인 코드를 구현할 수 있게 된다. Spring AOP도 아래에서 정리할 것이다.
    5. PSA(Portable Service Abstraction): 일관된 서비스 추상화. 클라이언트는 추상화된 상위 클래를 일관되게 바라보게 하면서 하위 클래스 기능을 사용하는 것이다. 인터페이스를 통한 느슨한 결합을 추구한다. 이렇게 되면 어떤 구현체를 사용하던간에 일관된 방식으로 사용할 수 있 기술을 유연하게 사용하는 것이 가능하다.

    원래 알고 있었던 것에 훨씬 많은 내용을 추가할 수 있었다. 특히 POJO에 관련된 부분이라던가, PSA라는 개념에 대해 알 수 있었다. DI와 AOP는 아래에서 더 집중적으로 공부했는데 느낀점을 간단히 적어보자면 내가 알고 있던 건 정말 빙산의 일각이었다는 사실..!!! 딱 그 개념에 대해서 한 줄로 설명할 수 있는 정도로만 알고있었다면 이번에는 실습과 함께 작동 원리를 이해하면서 훨씬 깊은 수준으로 이해하게 되었다고 생각한다. 그런데 참 스프링이라는 건 공부할 수록 깊고, 왜 사람들이 스프링은 러닝커브가 높은 기술이라고 하는지 알 것 같다. 스프링 핵심가치들은 정말 많은 고민 속에서 발전하고 있다는 생각이 든다. 앞으로 많은 시행착오를 겪게 될 것 같다. 정말정말 많은 걸 얻어가고 싶다.


    [DI(Dependency Injection)]

    🖍️ Spring Bean은 스프링 컨테이너에 등록된 자바 객체이다. 스프링 컨테이너는 Bean들의 생명주기, 의존성 주입까지도 제어하고 관리해준다. Bean을 만들 때 생성 정보인 Bean Definition과 비즈니스 로직을 받아서 context 생성 시점에 모두 불러와 Bean을 생성한다. BeanFactory는 Bean으로 설정된 객체를 생성하고 관리해주는 컨테이너 최상위 인터페이스이고, ApplicationContext는 BeanFactory를 상속받아 BeanFactory 기능 외에 여러 부가기능을 제공한다.
    Bean Scope는 Bean Definition에 정의되는데 Bean이 존재할 수 있는 범위를 나타낸다. Spring Framework에서 기본값은 singleton이다. 스프링 컨테이너 시작~종료까지 하나의 공유 인스턴스만 생성해서 관리하는 패턴이다. (singleton registry)
    Java 기반 컨테이너 설정의 핵심은 @Bean과 @Configuration이다. 설정 클래스에 @Configuration을, 빈으로 등록할 객체를 리턴하는 메서드에 @Bean을 달면 Bean으로 등록된다. @ComponentScan과 @Component를 사용할 수도 있다. @SpringBootApplication에는 @ComponentScan이 내장되어있다. @Component를 찾아 Bean으로 등록해주는데, @Bean과 달리 클래스 레벨에 적용하는 애너테이션이다. 스테레오 타입 애너테이션(@Controller @Service @Repository 등)에는 모두 @Component가 포함되어있다. 클래스 레벨에 적용하기 힘든, 즉 수동으로 객체를 관리해줘야하는 외부 라이브러리나 써드파티 클래스는 @Bean을 적용해서 관리하면 된다.
    그래서 DI란 무엇일까! IoC를 구체화해주는 방법 중 하나인데, 의존성 주입이다. 객체 간의 결합도를 낮추기 위해 최대한 객체 간의 의존을 줄여야 한다. 그러기 위해서는 객체 내부에서 new를 통한 의존 관계 형성은 지양해야 하고, 생성자를 통해 외부에서 주입해주는 것이 바람직하다. (그 외에도 Setter, 필드 주입 등의 방법이 있지만.) @Component와 @Autowired를 사용하면 스프링 컨테이너가 Bean 생성과 의존성까지 함께 관리해준다. @Autowired는 의존성 주입에 필요한 설정 정보 대신, 자동으로 의존 관계 설정을 해준다. 생성자가 하나만 존재할 경우 @Autowired를 생략해도 자동으로 의존성이 주입된다(4.3부터).

    학습하고 설명을 들을 때는 전부 이해했다고 생각했는데 정리하면서 되게 헷갈렸다. @Configuration-@Bean / @ComponentScan-@Component 차이는 알겠는데 사용해보지 않아서 그런가 용도에 맞게 적절히 사용하는 방법에 대해 이해가 되지 않았다. 구글링도 해보고 친구한테도 물어가봐면서 우선 정리한 내용은>> 보통 컨트롤러나 서비스같은 비즈니스 로직은 Component로 관리가 되기 때문에 @ComponentScan(SpringBootApplicaiton에 내장, Spring같은 경우에는 main에 ComponentScan을 달아서), 무언가를 설정하는 용도의 클래스는 @Configuration을 달아주는데 이것 또한 Component를 가지고 있어 Component로 관리되는 것은 똑같다 => 용도에 맞게 명시해주는 것. 개념에 대해서는 이해가 된 것 같은데 차차 더 많은 유닛을 학습하면서 실제로 적용해보는 게 중요할 것 같다! 아까 든 생각인데 예전에 살짝 만들어봤던 토이프로젝트를 리팩토링해보면서 익히면 더 좋을 것 같다.


    [AOP(Aspect Oriented Programming)]

    🖍️ AOP는 직역하자면 관심 지향 프로그래밍이다. Aspect라는 모듈 형태로 핵심 기능 외의 부가 기능을 정의해서 사용한다. (부가 기능, 횡단 관심사) 애플리케이션 전반에서 불특정 다수 클래스에 적용되어야 하는 부가 기능(중복 코드)을 분리해내서, 애플리케이션을 더욱 객체지향적으로 만들어준다. 부가 기능에는 로깅, 트랜잭션, 보안 등이 있다.
    Aspect에는 여러 Advice와 JoinPoint가 함께 존재한다. 우선 JoinPoint는 애플리케이션 실행 흐름에서 특정 포인트를 의미한다. 클래스 초기화, 객체 인스턴스화, 메서드 호출 등 여러 포인트가 있지만 Spring AOP는 프록시 방식을 사용하기 때문에 메서드 호출 지점으로 제한된다. (애플리케이션 실행 전 Bean 생성과 함께 프록시 객체가 생성된다: Bean 등록 되지 않는 객체는 AOP 적용 불가한 이유이기도)
    Advice는 JoinPoint에서 수행되는 코드, 또 그것을 언제 적용할 지를 정의한다. 적용 지점에 따라 Before(조인포인트 실행 이전), AfterReturning(정상 동작 후), AfterThrowing(예외 던지는 경우), After(정상/예외에 상관 없이), Around(전후, 가장 강력)로 나뉜다.
    Weaving은 AOP가 구현되는 과정이다. Advice를 핵심 코드에 적용하는 것이다.
    Pointcut은 JoinPoint 중 Advice가 적용될 지점을 선별하며, AspectJ 표현식을 사용한다. Pointcut 지시자로 시작한다. execution(메서드 실행 JoinPoint 매칭), within(특정 타입 내의 JoinPoint), args, this, target, @target ..... 등 여러 지시자가 존재하지만 주로 execution을 사용한다. &&, ||, !을 통한 결합도 가능하고, 이름으로 Pointcut 표현식을 참조할 수도 있다. 아래 코드에서는 "allOrder()"

    @Pointcut("execution(* com.example.myapp.order..*(..))")
    private void allOrder() {}

    @AspectJ는 애너테이션이 있는 일반 Java 클래스로 관점을 선언하는 스타일이다. Pointcut 구문 분석을 위해서 스프링은 AspectJ가 제공하는 라이브러리를 사용해서 AspectJ5와 동일한 애너테이션을 해석한다. 하지만 AspectJ 컴파일러나 위버에 의존하지 않는 순수한 Spring AOP이다. @AspectJ를 활성화하기 위해서는 설정 클래스에 @EnableAspectJAutoProxy 애너테이션을 추가해준다. 그러면 @Aspect가 있는 클래스로 정의된 Bean이 자동 감지되어 Spring AOP를 구성하는 데 사용된다.

    AOP를 학습하면서 가장 힘들었던 점은 용어였다. 중복되거나 애매한 내용이 정말 많다. 직접 적용해보고 하나하나 살펴보지 않는 이상 글만 읽어서 이해하는 건 불가능했다. 그래도 실습을 통해서 여러 방식의 Pointcut이나Aspect를 작성해보니까 처음만큼 혼란스럽지 않다. 아직 애너테이션을 이용한 AOP에 대해서는 이해가 더 필요할 것 같다. 아ㅏㅏㅏ 나에게 AOP는 아직까지 직접 적용해보지 않고는 와닿지 않는 기술이다. 예전에 로그인 체크를 AOP로 구현해볼까 라는 생각도 했었는데 굉장히 무모했던 생각이었다. 지금보다도 훨씬 AOP에 대한 이해가 적었고 사실 뭔지도 몰랐는데 구글링 해보고 이런 게 있대! 라는 의견을 냈었기 때문에... 그래도 이제는 세션에서 이야기한대로 어떻게 사용하는 것이고, 왜 필요한 건지에 대해서는 충분히 이해가 된 것 같아서 그 점은 다행이다. 당장 활용할 일이 없는 기술이라고 해서 소홀히 하고 넘어가지는 않도록 하려고 한다. 같은 실수를 반복하지는 말자..!!!🥹


    [Spring Framework 모듈 구성]

    💚아키텍처는 어떠한 시스템 구성을 큰 그림으로 표현한 것이라고 볼 수 있다. 그 중 웹 애플리케이션을 위한 아키텍처, 또 그 중에서도 계층형 아키텍처에 대해 간단히 설명하자면 다음과 같다.

    웹 애플리케이션_계층형 아키텍처

    API 계층: 클라이언트의 요청을 받아들이는 계층. REST API 제공
    서비스 계층: API 계층에서 전달받은 요청을 업무 도메인 요구사항에 맞게 처리. 핵심 비즈니스 로직 존재
    데이터 액세스 계층: 서비스 계층에서 처리된 데이터를 DB 등 저장소에 저장

    https://docs.spring.io/spring-framework/docs/5.0.0.M5/spring-framework-reference/html/overview.html

    모듈은 일반적으로 지원되는 여러 기능을 목적에 맞게 그룹화해둔 것이다. Java에서는 주로 패키지 형태로 묶여 라이브러리 형태로 제공된다. 위 그림은 Spring에서 제공되는 모듈을 아키텍처 별로 표현한 그림이다. Spring은 약 20개의 모듈을 통해 다양한 기능을 제공한다.
    1. Core Container
    spring-beans, spring-core: IoC 포함 프레임워크 기본 기능 제공. BeanFactory 구현. 우리가 코드를 칠 때 따로 singleton 구현을 고려하지 않아도 된다고 하는 것은 Spring container의 BeanScope 기본 설정이 singleton이기 때문인 듯 하다.
    spring-context: BeanFactory 개념 확장. resource loader, 환경 설정(properties 등)... Spring이 Bean을 다루고 추가적인 기능을 하기 위해 설정된 공간인 context 관리.
    spring-expression: 런타임에 객체 그래프(객체 간의 참조 관계를 통해 형성된 그룹)를 조작, Bean 속성(배열, 컬렉션 포함), 연산자, 변수 등 Spring의 IoC 컨테이너에서 이름으로 객체 검색 지원하는 표현 언어 제공.
    2. AOP, Aspect
    spring-aop: 관심 지향 프로그래밍을 위한 기능 제공. 메서드 인터셉터 및 포인트컷 정의 등
    spring-aspects: AspectJ와의 통합 제공. 이것들을 통해 AspectJ 컴파일러에 의존하지 않을 수 있는 듯하다.
    3. Web
    spring-web: 웹 지향 통합기능 제공. multipart 파일 업로드, 서블릿 리스너 및 web oriented 애플리케이션 컨텍스트를 사용하는 IoC 컨테이너 초기화 등 기본 웹 기능.
    spring-mvc: 자체 MVC 프레임워크제공. 웹 애플리케이션 REST 서비스 구현 등.
    4, Test
    spring-test: jUnit 등을 사용한 단위/통합 테스트 지원

    회고를 작성하면서 처음으로 그림을 사용한 것 같다. 그림 없이는 정리하기 어려운 부분이라 넣어보았다. Spring 모듈은 부족하지만 공식문서에 있는 내용 중 지금까지 배운 내용과 관련있는 것 같은 부분을 정리해보았다. 틀린 부분이 있을 수도 있지만, 직접 각 모듈을 살펴본 건 처음이라서 굉장히 의미있는 회고 시간이었다.
    Core Container의 context는 읽으면서 잘 이해가 되지 않아 서치를 많이 해봤는데, 보통 컨테이너 안에 컨텍스트가 존재하고, 그 컨텍스트에 빈이 존재한다는 걸 알 수 있었다. 생각해보니 스프링 컨테이너를 객체화할 때 사용했던 "ApplicationContext" 인터페이스의 context가 여기에 연관된 거구나 하는 생각을 했다. 아직 모르는 것도 많고 문서가 영어로 되어있다보니 한번에 와닿지는 않았지만 그간 해왔던 실습들과 배운 개념들을 통합해서 생각해보니 생각보다 이해할 수 있는 모듈이 많이 있었고 퍼즐이 맞춰지는 느낌이 들어서 재미있었다.


    [Spring Boot 소개]

    💚 Spring Boot를 사용하는 경우 설정이 굉장히 간단해진다. 그래서 우리는 비즈니스 로직 구현에 더 집중할 수 있게 된다. Spring Boot에서의 설정은 XML 기반의 복잡한 설계방식을 이용하지 않고, 의존 라이브러리 또한 간단한 코드 몇 줄로 작성하면 라이브러리의 이름과 버전을 일일이 수동으로 설정해주지 않아도 되어 아주 간단하다. 또 jar 파일로 빌드가 쉽고, 톰캣이 내장되어 있어 실행도 간단하다.


    나는 개발을 처음 배웠을 때 jsp, servlet을 시작으로 spring mvc까지 학습했는데, 처음에는 의존 라이브러리를 maven repository에서 찾아 수동으로, 버전별로 하나하나 설정해줘야 했고, 그 뿐만 아니라 db 연결 등 엄청 많은 설정들을 이해하는 데도 오래 걸렸다. 그래서 더 깊게 파려하지 않고 설정을 복붙하거나 소홀하게 넘기진 않았을까 하는 생각이 든다. web.xml을 작성하는 것도 태그 관리를 하느라 머리아프고 실제로 설정에만 되게 많은 시간을 할애했었다. Spring Initializr를 이용해서 Spring Boot 프로젝트를 엄청 빠른 시간에 클릭 몇 번으로 생성할 수 있는 게 정말... 좋고ㅎㅎㅎ 감사하다


    🌱 Unit 7-8. Spring framework를 마치고!

    두 유닛이 중복되는 내용이 많아서 두 유닛을 같이 다루는 게 좋다고 생각했는데, 조금... 잘못된 생각이었던 것 같기도 하다ㅎㅎ 그 이유는 단순하다. 내용이 굉장히 길어져서 포스팅에 많은 시간이 필요했기 때문이다! 먼저 DI, AOP를 제외한 Unit 7의 내용을 다 정리하고 났는데 진이 빠져서 주말까지 끌고 와버렸다. 무튼 이번 회고는 길고 힘들었던만큼 참 의미있다. 포스팅 시간이 길어진 건 내용이 많아서도 있지만 정리를 하면 할수록 조금 더 알아보고 싶은 내용이 많아져서 자꾸 파고들다 보니 이렇게 된 것 같다. 특히 공식문서를 간단히 읽어보려고 하다가 이건 뭘까 이건 뭘까 하면서 너무 많은 시간을 보내버렸다! 잘못된 건 아니지만 나는 항상 뭐든 국소적으로 파고들어버리는 경향이 있어서 흐름을 놓치는 일이 있는 것 같다. 조금 더 지금 당장에 집중하고 미룰 건 미룰 수 있어야 되는데 그러다가 어려운 개념이 나와버리면 조금은 좌절해버리니, 신경쓰면서 공부해야겠다. 그래도 회고를 통해 새로운 개념을 알아가고 또 거기서 흥미를 느꼈으니 됐다 이말이야
    아무튼 처음 시작할 때부터 지금까지 의미가 없는 유닛들은 없었지만 스프링은 나한테 조금 특별하다. 처음 학습할 때 잘못된 학습을 했다고 생각해서이다. 물론 내 학습 방식에도 문제가 있었지만... 그냥 이런저런 이유들로 개념을 제대로 잡지 못하고 "모르는 채로" 사용해 온 대표적인 기술이라는 생각이 든다. 파면 팔수록 어렵고 얼마든지 깊고 어려운 내용으로 갈 수 있는 게 스프링인데 앞으로 잘 할 수 있을지도 걱정되고 같은 실수를 반복하게 되지는 않을까 싶어서 더 많은 생각이 드는 것 같다... 그래도 지금까지는 나름 잘 따라가고 있는 것 같으니 그냥 나를 믿고 칭찬해주는 게 좋을 것 같다! 그리고 계속 학습을 진행해오면서 그래도 나만의 목표가 생기고 계획이 생기니까 어떤 방식으로 어떤 점을 보완해야 할 지가 보이는 것 같아서 기쁜 요즘이다. 객체지향을 위한 고민을 얼마나 많이 했는지 배울수록 느껴지는 Spring framework 회고 끝

    반응형

    댓글