Spring Framework

JooH·2024년 2월 13일
0

NHN_BackendAcademy

목록 보기
10/23

프레임워크와 라이브러리의 차이

공통점 : 특정 문제를 일반적으로 해결하기 위한 코드 제공, 재활용 가능
프레임워크는 원하는 기능을 구현하기 위해 일정한 형태를 제공한다.
ex) 레디스 (프레임워크 vs 라이브러리)

프레임 워크 쓰는 이유? 생산성의 증가.
기능적 요구사항 : 비즈니스에 직접적
비 기능적 요구사항 : 속도 등..

프레임 워크를 사용하면 비즈니스 로직에 집중해서 개발이 빨라지게 해준다.

어떤 프레임 워크/라이브러리를 써야 할까?
남들이 많이 쓰는 (표준)것을 쓰면 된다. 생태계가 확보 되어있으면 업데이트 등 자주 해준다.

Spring Framework : 자바 엔터브라이즈 개발을 편하게 해주는 오픈소스 경량금 app framework

Spring Framework 특징:
1) 경량 컨테이너로 Spring Bean을 직접 관리
2) POJO 기반의 프레임워크 - 기존에 존재하는 라이브러리 사용하기 편함
3) 제어역전(IOC)

    - 컨트롤의 제어권이 사용자가 아니라 프레임워크에 있어서 필요에 따라 스프링에서 사용자의 코드 호출
    - 의존성 주입(Dependency Injection)
	- TDD(테스트 주도 개발), DDD(도메인 주도 개발)같은 개발론에도 적합한 프레임 워크이다.

4) 관점 지향 프로그래밍(AOP) 지원
5) 영속성과 관련된 다양한 서비스 지원 - Mybatis, Hibernate, JdbcTemplate등

Spring Framework Module

Spring Core Container:

AOP:

Data Access/Integration, Web, Test
Jdbc~oxm : DB
spring-test : 테스트케이스는 모든 언어에서 매우 중요
ex) 동떨어진 기능 A, B를 만드는데 A기능이 B기능에 의해 작동 안되는 경우가 있음
따라서 테스트커버리지를 매우 넓게 잡아서 기능을 견고하게 만든다.
서비스를 하게 되면 지속 가능한 프로그램을 유지하게 된다. 버그가 없는 프로그램은 사용하지 않는 프로그램. 따라서 테스트케이스를 다양하게 구성해서 커버리지를 높여야 한다.
spring-web : doPost, doGet등에서 jsp 연결, 이런 과정을 모르고 쉽게 사용하게 해준다.

Spring Projects

Spring Boot vs Spring Core(Framework)?
-지금은 Spring Boot가 대세는 맞음

  • Out-Of-Box : WebServer가 내장되어있어서 Tomcat을 안쓰고 사용가능해짐

Spring Framework Dependencies
Compile타임에서 에러가 나면 개발자가 수정이 가능하다(운이좋음). 하지만 RuntimeError는 잡기도 어렵고 사용자 경험으로 이어진다(운이나쁨).
spring-framework-bom : Maven 버전관리를 도와줌. Spring Framework 버전 내부에서 (호환되는) 버전을 잡아줌. 같은 모듈 내부에서는 99%까지 버전충돌을 잡아준다.

Spring Triangle (스프링 3대 구성)

사실 굳이 따지면 DI보다는 IOC가 더 옳다
PSA를 쉽게 설명하자면, 개발자가 DB layer를 신경쓰지 않고 개발하게 해주는 것이다.

다형성 (Polymorphism)
다형성의 구현 : 오버로딩, 오버라이딩, 함수형 인터페이스로 구현할 수 있다.
*tmi) 스태틱 메소드는 클래스 인스턴스를 생성하지 않고 호출할 수 있다.

다형성에서 다음과 같이 interface를 구현한 concrete Class가 바인딩 되는 시점은 컴파일 시점에 알 수 없다. <<중요

캐스팅에는 두 종류가 있다 : 업 캐스팅, 다운 캐스팅
업 캐스팅 : 상위 인터페이스에서 하위 구현체의 메소드를 사용
다운 캐스팅 : 하위 클래스에서 상위 클래스의 메소드를 사용하는것

IOC : 제어 역전(inversion of Control)

  • 제어권을 프레임워크가 갖는것 == 개발자는 제어권이 없다 == 제어가 역전되었다.
  • 제어 : 1) 프로그램의 흐름, 2) 객체의 생성

객체의 생애주기도 프레임워크가 관리한다.
IOC 관점에서 각자의 역할 :
프로그래머 : 코드의 흐름, 객체 생성에 관여 X, 프레임워크가 제공하는 설정 방법을 사용해 코드를 설정만 한다.

  • 제어 역전을 통해서 프로그래머는 비즈니스 로직에만 집중할 수 있게 된다.

프로그램의 흐름 예제 : Hollywood 예제

Hollywood Principle : Don't call us, We'll call you.
객체지향 프레임워크와 클래스 라이브러리의 가장 큰 차이점 : 프레임워크가 app 코드를 호출한다는 것. 일반적으로는 app 코드가 클래스 라이브러리를 호출함. --> Hollywood 원칙이라고도 한다.

IOC 구현 방법 : DI, Template Method Pattern 등을 통해 구현 가능함

IOC의 예 - 흐름의 제어 역전 (template method pattern)

template (형판, 틀) + 메서드 + 패턴
추상 클래스에 탬플릿에 해당하는 메소드에서 실행의 흐름이 이미 결정되어 있음.
단, 각 메소드가 구체적으로 어떤일을 할 것인지는 개발자의 구현에 따라 결정됨.
preProcess() -> mainProcess() -> postProcess()
javax.servlet.Filter interface


서블릿 필터에서 제공하는 인터페이스로 우리가 구현하여 쓰기만 하면 알아서 작동된다.

public abstract class AbstractProcessor {

    public final void process() {
        preProcess();
        mainProcess();
        postProcess();
    }

    protected abstract void preProcess();
    protected abstract void mainProcess();
    protected abstract void postProcess();
}

public class ConsoleLogProcessor extends AbstractProcessor {

    @Override
    protected void preProcess() {
        System.out.println("preProcess");
    }

    @Override
    protected void mainProcess() {
        System.out.println("mainProcess");
    }

    @Override
    protected void postProcess() {
        System.out.println("postProcess");
    }
}

다른 예시로, final method에 abstract method를 적어 구현 순서를 고정하는 예시를 볼 수 있다. 템플릿 메소드는 위와 같이 순서를 고정하고자 할때 주로 사용한다. 즉, 흐름에 대한 제어권 역전을 이렇게(이런식으로도) 사용한다 라는 예시를 보았다.

객체 생성의 제어역전 예시

public class NonIocMain { // 제어권 역전 X

    public static void main(String[] args) {
        new ComplexGreetingService().greet();
    }
}
public class ComplexGreetingService {

    /* ComplexGreetingService 내부에서 생성한 객체를 사용한다.*/
    public boolean greet() {
        return new KoreanGreeter().sayHello();
    }
}  

public class IoCMain { // 제어권 역전 O
    public static void main(String[] args) {
        new GreetingService(new KoreanGreeter()).greet(); // 의존관계 주입
    }
}
public class GreetingService {
    private final Greeter greeter; // 인터페이스와만 관계를 맺음

    public GreetingService(Greeter greeter) { // 의존관계 생성자로 주입
        this.greeter = greeter;
    }

    public void doGreet() {
        greeter.sayHello(); // Main에서 주입된 (new KoreanGreeter().sayHello()
    }
}

즉 NonIocMain에서는 ComplexGreetingService를 수정해야 내용이 바뀌었지만,
IocMain에서는 Main에서만 바꿔주면 된다. (주입하기 나름)

ApplicationContext (BeanFactory, IoC Container 거의 같은 개념이라 봐도 된다)

/아닐수도 있음/
BeanFactory : 가장 기본적인 IOC 컨테이너로, 기본 IoC 컨테이너 기능을 제공. 요청시 Bean을 Load 하므로 ApplicationContext보다 가볍다. 즉, Bean이 필요할 때만 Bean을 Load한다.

ApplicationContext : BeanFactory의 기능을 확장한 것. 모든 Bean을 시작시점에 Load. Bean에 비해서 무거운 IoC 컨테이너로 간주됨.

IoC 컨테이너 : BeanFactory, ApplicationContext를 포함하는 개념으로 Bean 정의를 Load하고 Bean을 서로 연결하며, 요청에 따라 Bean을 제공한다

ApplicationContext : 사용자의 설정을 읽고 Bean을 만들어서 의존관계를 주입해주는 역할을 한다.

Spring IoC Container
Spring Bean

!!Spring Beans은 JavaBeans과는 다르다!!

Bean Factory vs ApplicationContext
*Spring IoC container = {Bean Factory | ApplicationContext}

Bean Factory
*The BeanFactory API provides the underlying basis for Spring’s IoC functionality

ApplicationContext - central interface within a Spring application for providing configuration information to the application

기능 :

- Bean Factory Methods for accessing application components
- The ability to load file resources in a generic fashion.
- The ability to publish events to registered listeners.
- The ability to resolve messages to support internationalization.
- Inheritance from a parent context. 

Application Context는 다양한 종류가 있다.

- ~Xml~ApplicationContext
- ~AnnotationConfig~ApplicationContext
- ~Groovy~ApplicationContext
- ~Web~ApplicationContext

결국 Application Context의 가장 중요한 역할은 Bean 관리이다.

Spring Bean 생명주기 설정

Spring Bean 객체의 생명주기 설정은 IoC 컨테이너가 관리한다.

Bean Scope
SingleTon - default (대부분 싱글톤 사용)
Prototype
*Only vaild in the context of a web-aware Spring ApplicationContext

- request : lifecycle of a single HTTP request
- session : lifecycle of an HTTP Session
- application : lifecycle of a ServletContext
- websocket : 1ifecycle of a WebSocket

Singleton vs Prototype

  • Singleton
  • Prototype

객체의 생명주기 Callbacks - 초기화
org.springframework.beans.factory.InitializingBean 인터페이스를 구현한 빈은 생성시에 초기화 작업을 수행할 수 있다.
InitializingBean 은 afterPropertiesSet() 이라는 단일 메서드를 가진다.

void afterPropertiesSet() throws Exceptions

Spring Bean으로 등록하지 않으면 afterPropertiesSet()을 선언해야 한다.

XML빈 설정에서 init-method에 초기화 method 이름을 지정하여 초기화 작업을 등록할 수 있다.

<bean id="koreanGreeter" class="com.nhn.edu.springframework.ioc.helloworld.EnglishGreeter"
init-method="init"//이부분 이름 변경하면 됨>

이것들이 가능한 이유는 Spring에서 관리하는 Spring Bean이기 때문이다.

객체의 생명주기 Callbacks - 소멸
org.springframework.beans.factory.DisposableBean 인터페이스를 구현한 빈은 소멸시에 호출된다.
DisposableBean 은 destroy() 이라는 단일 메서드를 가진다.

void destroy() throws Exception;

init과 마찬가지로 xml Bean 설정에서 init-method에 초기화 메서드 이름을 지정하여 초기화 작업을 등록할 수 있다.
단, Destroy의 경우 Singleton에서만 호출이 된다.

그 이유는 싱글톤 범위의 빈은 컨테이너에서 한번만 생성되고, 그 이후로는 동일한 인스턴스가 재 사용되기 때문에 컨테이너가 종료될 때, destroy-method가 호출되서 빈의 리소스를 정리할 수 있다.
하지만, 프로토타입 범위의 빈은 매번 새로운 인스턴스가 생성된다. 따라서 컨테이너는 프로토타입 범위의 빈을 생성, 초기화 한 후에는 관리하지 않는다.
따라서 destory-method가 호출되지 않는다.

객체의 생명주기 - BeanPostProcessor
Spring IoC의 생명주기 처리를 변경할 수 있는 확장 포인트
BeanPostProcessor가 설정되면 생명주기 이벤트를 가로채서 처리할 수 있다.

구현 메소드 :

- postPostBeforeInitialization : init-method 에 지정된 메서드가 호출되기 전에 호출된다.
- postPostAfterInitialization : init-method 에 지정된 메서드가 호출된 후에 호출된다.
- init-method 가 지정되어 있지 않더라도 자동으로 호출된다.

0개의 댓글