본문 바로가기

프로그래밍(TA, AA)/JVM 언어

[스프링] 스프링 프레임워크 5.0 (1)

스프링 프레임워크


"스프링 프레임워크는 최신 자바-기반 엔터프라이즈 애플리케이션을 위한 포괄적인 프로그래밍 및 구성 모델을 제공한다."


스프링 프레임워크는 엔터프라이즈 자바 애플리케이션을 연결하는데 사용된다. 스프링 프레임워크의 주요 목표는 애플리케이션의 여러 부분을 연결하는데 필요한 모든 기술을 제공하고 전담 처리하는 것이다.


스프링 프레임워크가 중요한 이유는 "단순화된 단위 테스팅 / 복잡한 코드 감소 / 아키텍처의 유연성" 등이 있다.



단순화된 단위 테스팅

스프링 프레임워크의 의존성 주입은 의존성을 자신의 mock로 쉽게 대체함으로써 단위 테스팅을 가능하게 한다. 단위 테스트를 위해 전체 애플리케이션을 배포할 필요가 없다.



복잡한 코드 감소

스프링 프레임워크 이전의 일반적인 J2EE 애플리케이션에는 복잡한 코드(데이터베이스 연결 / 예외 처리 코드 / 트랜잭션 관리 코드 / 로깅 코드 등)가 포함됐다. 


스프링 JDBC(Java Database Connectivity)는 checked exception 대부분을 unchecked exception으로 변환한다. 일반적으로 쿼리가 실패하면 실행문을 종료하고 트랜잭션을 실패하는 것 외에는 할 수 있는 일이 많지 않다. 모든 메서드에서 예외 처리를 구현하는 대신, 중앙 집중식 예외처리를 수행하는 것이 가능하다. 스프링 JDBC는 커넥션을 가져오고, Prepared Statement를 생성하는 것과 관련된 모든 복잡한 코드를 생성할 필요가 없다. jdbcTemplate 클래스는 spring context에서 생성돼 필요할 때마다 DAO(Data Access Object) 클래스에 삽입될 수 있다. 이와 마찬가지로 스프링 JMS, 스프링 AOP 및 다른 스프링 모듈들 역시 복잡한 코드를 줄이는데 도움이 된다. 트랜잭션 관리, 예외 처리 등과 같은 모든 코드가 한곳에서 구현되므로 유지관리가 더 쉽다.



아키텍처의 유연성

스프링 프레임워크는 모듈식이다. 핵심 스프링 모듈 위에 구축된 독립적인 모듈 세트로 구축된다. 대부분의 스프링 모듈은 독립적이다. 다른 모듈을 사용하지 않고 한가지만 사용할 수 있다.


- Web Layer에서 스프링은 독자적인 프레임워크인 스프링 MVC를 제공한다. 그러나 스프링은 스트럿츠, 바딘, JSF 등등 원하는 웹프레임워크를 지원한다.

- 스프링 빈즈는 비즈니스 로직을 위한 경량 구현체를 제공할 수 있다.

- Data Layer에서 스프링은 스프링 JDBC 모듈을 사용해 JDBC를 단순화한다. 그러나 스프링은 JPA(Java Persistence API), Hibernate 또는 iBatis와 같이 원하는 데이터 레이어 프레임워크를 지원한다.

- 스프링 AOP를 사용해 횡단 관심(로깅, 트랜잭션 관리, 보안 등)을 구현할 수 있다.


스프링은 애플리케이션의 서로 다른 부분들 간의 결합을 줄이고, 이를 테스트할 수 있게 만드는 핵심 작업에 중점을 두면서 사용자가 선택한 프레임워크와의 훌륭한 통합을 제공한다. 특정 프레임워크를 사용하고 싶지 않으면, 다른 프레임워크로 쉽게 대체할 수 있다. 아키텍처에 융통성을 가질수 있게 된다.


스프링 프레임워크는 스프링 프로젝트의 많은 프로젝트 중 하나일 뿐이다. 


- 스프링 배치는 Java Batch Application에 대한 새로운 접근 방식을 정의한다. 자바 EE는 자바 EE 7에서야 비슷한 Batch Application Spec이 생겨났다.

- 아키텍처가 클라우드 및 마이크로서비스로 진화함에 따라 새로운 클라우드-기반 스프링 프로젝트가 나타났다. 스프링 클라우드는 마이크로서비스의 개발 및 배포를 단순화하는데 도움을 준다. 스프링 클라우드 데이터 플로는 마이크로 서비스 애플리케이션과 관련된 orchestration을 제공한다.




스프링 모듈


스프링 프레임워크는 20개 이상의 다른 모듈(경계가 명확)을 갖고 있는 고도화된 모듈이다.


 - 코어 (빈즈 / 코어 / 컨텐스트 / SpEL)

 - 횡단관심 (AOP / ASPECT / Instrumentation)

 - 웹 (Web / Servlet / WebSocket / 포틀릿)

 - 비즈니스 (트랜잭션)

 - 데이터 (JDBC / ORM / OXM / JMS / 메시징)



스프링 코어 컨테이너

Spring Core Container는 스프링 프레임워크 의존성 주입, IoC 컨테이너 및 Application Context의 핵심 기능을 제공한다.

spring-core: 다른 스프링 모듈이 사용하는 유틸리티

spring-beans: 스프링 빈 지원. 스프링-코어와 함께 스프링 프레임워크의 핵심 기능인 의존성 주입을 제공한다. BeanFactory의 구현을 포함

spring-context: BeanFactory를 상속하는 Application Context를 구현하고 리소스 로드 및 Localization 지원을 제공.

spring-expression: EL(JSP에서 표현 언어)을 확장하고 Bean 속성(배열 및 컬렉션 포함) 및 접근, 처리를 위한 언어를 제공한다.



횡단 관심

횡단 관심은 로깅/보안과 같은 모든 Layer에 걸쳐 적용할 수 있다. 단위 테스트와 통합 테스트는 모든 레이어에 적용할 수 있으므로 이 카테고리에 적합하다.

spring-aop: 메서드 인터셉터와 포인트 컷을 사용해 관점지향 프로그래밍에 대한 기본적인 지원을 제공

spring-aspects: 가장 인기있는 AOP 프레임워크 AspectJ와 통합을 제공

spring-instrument: 기본적은 instrumentation을 제공.

spring-test: 단위 및 통합 테스팅에 대한 기본 지원 제공.



스프링은 Struts와 같은 대중적인 웹프레임워크와 훌륭한 통합을 제공하는 것 외에도 자체 MVC 프레임워크인 스프링 MVC를 제공한다. 중요한 모듈/아티팩트는 다음과 같다.

spring-web: 멀티파트 파일 업로드와 같은 기본 웹기능을 제공한다. 스트럿츠와 같은 다른 웹프레임워크와의 통합을 지원

spring-webmvc: 모든 기능을 갖춘 웹 MVC 프레임워크를 제공한다. 스프링 MVC에는 REST 서비스를 구현하는 기능도 포함



비즈니스

비즈니스 레이어는 애플리케이션의 비즈니스 로직을 실행하는데 초점을 맞춘다. 스프링에서는 일반적으로 비즈니스 로직이 POJO로 구현된다. spring-tx는 POJO 및 다른 클래스에 대한 선언적 트랜잭션 관리를 제공한다.



데이터

애플리케이션의 데이터 레이어는 일반적으로 데이터베이스 또는 외부 인터페이스와 통신한다. 데이터 레이어와 관련된 중요한 스프링 모듈/아티팩트들은 아래와 같다.

spring-jdbc: 상용구 코드를 방지하기 위해 JDBC를 추상화.

spring-orm: ORM 프레임워크 및 스펙(JPA 및 하이버네이트 등)과의 통합을 제공

spring-oxm: XML 매핑 통합 객체를 제공. JAXB, Castor 등과 같은 프레임워크를 지원

spring-jms: 상용구 코드를 방지하기 위해 JMS를 추상화.




스프링 프로젝트


스프링 프레임워크는 Enterprise Application의 핵심 기능을 위한 기반을 제공하지만, 다른 스프링 프로젝트는 배포/클라우드/빅데이터/배치/시큐리티와 같은 엔터프라이즈 공간의 다른 문제에 대한 통합 및 솔루션을 제공한다. 중요한 스프링 프로젝트들은 다음과 같다.


스프링부트 / 스프링 클라우드 / 스프링데이터 / 스프링배치 / 스프링 시큐리니 / 스프링 HATEOAS



스프링 부트

마이크로서비스 및 웹 애플리케이션을 개발하는 동안 해결해야하는 과제.


 - 프레임워크 선택 및 호환 가능한 프레임워크 버전 결정

 - 외부화 구성을 위한 메커니즘 제공 (특정 환경에서 다른 환경으로 변경할 수 있는 속성)

 - 상태 점검 및 모니터링 (애플리케이션의 특정 부분이 다운된 경우, 알람 제공)

 - 배포 환경 결정 및 애플리케이션 구성


스프링 부트는 애플리케이션을 어떻게 개발해야하는지에 대한 고민을 해결해준다.



스프링 클라우드

클라우드-네이티브 마이크로서비스 / 애플리케이션은 IT 주목받는 화제 중 하나이다. 스프링은 스프링 클라우드로 클라우드용 애플리케잇녀을 개발하기 위해 빠르게 진보하고 있다. 스프링 클라우드는 분산 시스템의 일반적인 패턴을 위한 솔루션을 제공한다. 스프링 클라우드는 개발자가 공통 패턴을 구현하는 애플리케이션을 신속하게 생성할 수 있게 한다. 스프링 클라우드에서 구현된 일반적인 패턴 중 일부는 "구성관리 / 서비스 디스커버리 / 서킷 브레이커 / 지능형 라우팅" 등이 있다.



스프링 데이터

SQL 데이터베이스 및 다양한 NoSQL 데이터베이스와 관련된 여러 데이터 소스가 존재한다. 스프링 데이터는 이러한 모든 종류의 데이터베이스에 일관된 Data Access 방식을 제공한다. 스프링 데이터는 다양한 스펙/Data Repository와의 통합을 제공(JPA / MongoDB / Redis / Solr / Gemfire / Apache Cassandra)한다.


1. 메서드 이름에서 쿼리를 결정해 Repository 및 객체 매핑에 대한 추상화를 제공한다.

2. 간단한 Spring Integration

3. 스프링 MVC 컨트롤러와의 통합

4. 고급 자동 감사 기능 - 생성자, 생성일, 마지막 수정자, 마지막 수정일



스프링 배치

엔터프라이즈 애플리케이션은 Batch 프로그램을 사용해 대량의 데이터를 처리한다. 이러한 애플리케이션들의 요구 사항은 아주 유사하다. 스프링 배치는 고성능 요구 사항이 있는 대용량 배치 프로그램을 위한 솔루션을 제공한다.


1. 작업을 시작, 중지 및 재시작하는 기능(실패한 작업을 실패한 지점부터 재시작할 수 있는 기능 포함)

2. 데이터를 chunks로 처리하는 능력

3. 단계를 재시도하거나 실패한 단계를 건너뛸 수 있는 기능

4. 웹-기반 관리 인터페이스



스프링 HATEOAS

HATEOAS는 애플리케이션 상태 엔진인 하이퍼미디어를 나타낸다. 주요 목표는 클라이언트(서비스 소비자)로 부터 서버(서비스 공급자)를 분리하는 것이다. 서비스 공급자는 이용자에게 자원에 대해 수행할 수 있는 다른 조치에 대한 정보를 제공한다. 스프링 HATEOAS는 HATEOAS 구현체를 제공하는데, 특히 스프링 MVC로 구현된 REST 서비스에 적합하다. 


1. 링크가 깨지는 것을 줄이기 위해, 서비스를 제공하는 링크 정의를 단순화

2. JAXB(XML-기반) 및 JSON 통합 지원

3. 서비스 소비자 지원(클라이언트-사이드)




스프링 프레임워크 5.0 새로운 기능


스프링 프레임워크 5.0의 주요 변경 사항 중 하나는 스프링 부트 2.0의 새로운 기능들이다. 리액티브 프로그래밍도 주요한 특징이다. 핵심 리액티브 프로그래밍 기능과 엔드포인트 지원 기능을 스프링 프레임워크 5.0에서 바로 사용할 수 있다.


1. Baseline 업그레이드

2. JDK 9 런타임 호환

3. 스프링 프레임워크 토드에서 JDK 8 기능 사용

4. 리액티브 프로그래밍 지원

5. 함수형 웹 프레임워크

6. Jigsaw를 사용한 자바 모듈성

7. 코틀린 지원



Baseline 업그레이드

스프링 프레임워크 5.0은 JDK 8과 자바 EE 7 이전 버전은 더이상 지원되지 않는다.


하이버네이트5 / Jackson2.6 / EhCache2.10 / JUnit5 / 타일즈3

톰캣8.5+ / 제티9.4+ / 와이드플라이10+ / 네티4.1+(스프링 웹플럭스 지원) / 언더토우1.4+(스프링 웹플럭스 지원)


이전 버전의 모든 스펙/프레임워크를 사용하는 애플리케이션은 스프링 프레임워크 5.0을 사용하기 전에, 위에 나열한 버전으로 업그레이드해야 한다.



스프링 프레임워크 코드에서 JDK8 기능 사용

스프링 프레임워크 5.0의 기본 버전은 자바8이고, 스프링 프레임워크 코드가 자바8의 새로운 기능을 사용하도록 업그레이드 되었다. 사용된 자바8 기능 중 일부는 다음과 같다.

- 코어 스프링 인터페이스의 자바8 기본 메서드

- 자바 8 리플렉션 향상을 기반으로 한 내부 코드 개선

- 프레임워크 코드에서 함수형 프로그래밍 사용(람다와 스트림)



리액티브 프로그래밍 지원

마이크로 서비스 아키텍처는 일반적으로 이벤트-기반 통신을 기반으로 구축되고, 애플리케이션은 이벤트에 반응하도록 작성된다. 리액티브 프로그래밍은 이벤트에 반응하는 애플리케이션을 구현하는데 초점을 맞춘 프로그래밍 스타일을 제공한다. 리액티브 프로그래밍을 지원하는 다양한 프레임워크가 있다.


- 리액티브 스트림: 리액티브 API를 정의하려는 언어 중립적 시도

- 리액터: 스프링 피보탈 팀이 제공하는 리액티브 스트림의 자바 구현

- 스프링 웹 플럭스: 리액티브 프로그래밍을 기반으로 웹 애플리케이션을 개발할 수 있다. 스프링 MVC와 비슷한 프로그래밍 모델을 제공한다.



함수형 웹 프레임워크

스프링 5.0은 리액티브 기능을 바탕으로 함수형 웹 프레임워크를 제공하며, 함수형 웹 프레임워크는 함수형 프로그래밍 스타일을 사용해 엔드포인트를 정의하는 기능을 제공한다.

RouterFunction<String> route = route(GET("/hello-world"), request -> Response.ok().body(fromObject("Hello World")));


함수형 웹 프레임워크를 사용해 보다 복잡한 경로를 정의할 수도 있다.

RouterFunction<?> route =
	route(GET("/todos/{id}"),
		request -> {
			Mono<Todo> todo = Mono.justOrEmpty(request.pathVariable("id"))
				.map(Integer::valueOf)
				.then(repository::getTodo);
			return Response.ok().body(fromPublisher(todo, Todo.class));
		}
	)
	.and(route(GET("/todos"),
		request -> {
			Flux<Todo> people = repository.allTodos();
			return Response.ok().body(fromPublisher(people, Todo.class));
		})
	)
	.and(route(POST("/todos"),
		request -> {
			Mono<Todo> todo = request.body(toMono(Todo.class));
			return Response.ok().build(repository.saveTodo(todo));
		})
	);

 - RouterFunction은 일치하는 조건을 평가해 요청을 적절한 처리 함수로 라우트한다.

 - 3개의 엔드포인트, 2개의 GET + 1개의 POST를 정의하고, 서로 다른 Handler함수에 매핑한다.


모노와 플러스에 대해서는 리액티브 프로그래밍를 통해 더 자세히 알아볼 수 있다.



직소를 사용한 자바 모듈성

자바 플랫폼은 자바8이 나오기 전까지 모듈식이 아니었다. 그렇게 때문에 다음과 같은 문제점을 지니고 있었다.


플랫폼 무거움: IoT, Node.js와 같은 새로운 경량 플랫폼을 사용하면서 자바 플랫폼이 상대적으로 무거운 플랫폼에 속하였다.

JAR Hell: 자바 클래스 로더ㅇ가 클래스를 찾으면 사용 가능한 클래스에 대한 다른 정의가 있는지 알 수 없다. 발견된 첫번째 클래스가 바로 로드되어 버린다. 애플리케이션에서 필요한 특정 클래스가 여러 jar에 모두 있는 경우, 특정 jar에 있는 해당 클래스를 로드하도록 지정할 수 있는 방법은 없다.


OSGi는 1999년에 시작된 자바 프로젝트에 모듈성을 도입하려는 발의중 하나이다. 각 모듈(번들)은 다음과 같이 정의할 수 있다.


imports: 모듈이 사용하는 다른 번들

exports: 번들이 반출하는 패키지


각 모듈은 자체 생명 주기를 가질 수 있다. 자체적으로 설치, 시작 및 중지할 수 있다. 직소는 자바에 모듈성을 제공하기 위해 Java Community Process에서 발의됐다. 이는 두가지 주요 목적을 가지고 있다.


JDK용 모듈러 구조 정의 및 구현

자바 플랫폼에 구축된 애플리케이션용 모듈 시스템 정의



스프링부트 2.0의 새로운 기능


스프링 부트의 첫번째 버전은 2014년에 출시됐다. 다음은 스프링 부트 2.0에서 예상되는 중요한 업데이트 중 일부다.


- 기본 JDK 버전은 자바8이다.

- 기준 스프링 버전은 스프링 프레임워크 5.0이다.

- 스프링 부트 2.0은 Web-Flux를 이용한 리액티브 웹프로그래밍을 지원한다.


프로엠워크의 최소 지원 버전은 다음과 같다.


- 제티 9.4

- 톰캣 8.5

- 하이버네이트 5.2

- 그래들 3.4




스프링 IoC 컨테이너


스프링 IoC 컨테이너는 애플리케이션 개발자가 생성한 설정에 따라 빈을 생성하고 연결한다. 스프링 IoC 컨테이너는 @Autowired 어노테이션을 통해 빈와이어링(빈을 서로 묶는 방법)을 구현한다.


스프링 IoC 컨테이너를 생성하는데에는 BeanFactory/ApplicationContext 두가지 방법이 있다. BeanFactory는 모든 스프링 IoC 기능의 기초다. ApplicationContext는 기본적으로 엔터프라이즈 컨텍스트에서 일반적으로 필요한 추가 기능을 사용하는 BeanFactory의 상위 집합이다. 스프링에서는 ApplicationContext를 사용할 것을 권장한다. ApplicationContext는 자바 구성 또는 XML 구성을 가질 수있다.



스프링 MVC 기본 설정



웹애플리케이션에서 스프링 MVC 구성을 이해하기 위해, 간단한 웹애플리케이션 설정 단계는 다음과 같다.


1. 스프링 MVC에 대한 의존성 추가

2. DispatcherServlet을 web.xml에 추가

3. 스프링 애플리케이션 컨텐스트 생성



1. 스프링 MVC에 대한 의존성 추가

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-webmvc</artifactId>
</dependency>

DispatcherServlet은 프런트 컨트롤러 패턴의 구현이다. 스프링 MVC에 대한 요청은 프런트 컨트롤러, 즉 DispatcherServlet에 의해 처리된다.



2. DispatcherServlet을 web.xml에 추가

<servlet>
	<servlet-name>spring-mvc-dispatcher-servlet</servlet-name>
	<servlet-class>
		org.springframework.web.servlet.DispatcherServlet
	</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/user-web-context.xml</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
	<servlet-name>spring-mvc-dispatcher-servlet</servlet-name>
	<url-pattern>/</url-pattern>
</servlet-mapping>

첫번째 부분에서는 서블릿을 정의한다. Context의 구성위치도 정의하고 있다. 두번째 부분에서는 서블릿 매핑을 정의한다. 여기서 URL /을 DispatcherServlet에 매핑하고 있다. 따라서 모든 요청은 DispatcherServlet에 의해 처리된다.



3. 스프링 컨텐스트 생성

web.xml에 DispatcherServlet이 정의되었으므로 Spring Context를 만들 수 있다.

<beans>
	<context:component-scan
		base-package="com.matering.spring.springmvc" />
	<mvc:annotation-driven />
</beans>


com.mastering.spring.springmvc 패키지에 모든 빈 및 컨트롤러가 생성되어 autowired 된다.


<mvc:annotation-driven />을 사용하면, "요청 매핑/예외 처리/데이터바인딩 및 validation / @RequestBody 어노테이션을 사용하는 경우 자동 변환" 등 스프링 MVC가 지원하는 많은 기능에 대한 초기화를 제공한다.


[스프링 MVC 아키텍처의 핵심 컴포넌트 Flow]

1. 브라우저는 특정 URL에 요청을 보낸다. DispatcherServlet은 모든 요청을 처리하는 프론트 컨트롤러다. 그래서 DispatcherServlet이 요청을 받는다.

2. Dispatcher Servlet은 URL을 보고, 이를 처리하기 위해 올바른 컨트롤러를 식별해야 한다. 올바른 컨트롤러를 찾는데 도움을 주기 위해 핸들러 매핑과 통신한다.

3. 핸들러 매핑은 요청을 처리하는 특정 핸들러 메서드를 반환한다.

4. Dispatcher Servlet은 특정 핸들러 메서드를 호출한다.

5. 핸들러 메서드는 모델과 뷰를 반환한다.

6. DisaptcherServlet에는 논리적 뷰이름이 있다. 따라서 물리적 뷰이름을 결정하는 방법을 알아내야한다. 사용할 수 있는 뷰리졸버가 있는지의 여부를 확인한다. 설정된 뷰리졸버를 찾는다. 뷰리졸버를 호출해 논리적 뷰 이름을 입력으로 제공한다.

7. 뷰 리졸버는 논리적 뷰 이름을 물리적 뷰 이름에 매핑하는 로직을 실행한다.

8. DispatcherServlet은 뷰를 실행한다.

9. 뷰는 DispatcherServlet으로 보내질 내용을 반환한다.

10. DispatcherServlet은 응답을 다시 브라우저로 보낸다.