[File] → [New] → [Spring Legacy Project] 또는 [Other] 선택 후 생성 창에서 [Spring] → [Spring Legacy Project] 선택
Project Name 입력, Templates 선택 'Spring MVC Project' → com.reth.wiki 같은 형식의 패키지 명 입력
프로젝트 설정
프로젝트의 컨텍스트 메뉴 [Properties] 선택 → 왼쪽 트리메뉴 [Project Facetes] 선택 Java 버전 선택 수정
오른쪽 [Runtimes] 탭에서 Tomcat 버전 선택 → Apply → OK
확인
[Java Build Path] → [Libraries] 탭, 경로 확인
Basic File Structures
프로젝트
src/main/webapp/WEB-INF/web.xml; Servlet 컨테이너 설정
pom.xml
C:.
│ .gitignore // gitignore 파일
│ build.gradle // 빌드 스크립트
│ gradlew // gradle 실행 sh 스크립트
│ gradlew.bat // gradle 윈도우 실행 배치 파일
│ LICENSE // 라이센스 정보
│ README.md // 간단한 설명 파일
│ settings.gradle // gradle 설정 파일,
│
├─.gradle ... 생략(자동 생성) ...
├─.idea ... 생략(자동 생성) ...
├─build ... 생략(자동 생성) ...
├─gradle // gradle wrapper
│ └─wrapper
│ gradle-wrapper.jar
│ gradle-wrapper.properties
└─src
├─main // 애플리케이션 메인
│ ├─java // 패키지 작성
│ └─resources // mapper xml, configuration yml, etc.
│ application.yml // 기본 애플리케이션 설정
└─test // 애플리케이션 테스트
├─java // 테스트 작성
└─resources // 테스트용 resources
처리 영역
프레임워크
설명
Presentation
Struts
Struts 프레임워크는 UI Layer에 중점을 두고 개발된 MVC(Model View Controller) 프레임워크이다.
Spring
Struts와 동일하게 MVC 아키텍처를 제공하는 UI Layer 프레임워크이다. 하지만 Struts 처럼 독립된 프레임워크는 아니고 Spring 프레임워크에 포함되어 있다.
Business
Spring
(IoC, AOP)
Spring은 컨테이너 성격을 가지는 프레임워크이다. Springj의 IoC와 AOP 모듈을 이용하여 Spring 컨테이너에서 동작하는 엔터프라이즈 비즈니스 컴포넌트를 개발할 수 있다.
Persistence
Hibernate or JPA
Hibernate는 완벽한 ORM(Object Relation Mapping) 프레임워크이다. ORM 프레임워크는 SQL 명령어를 프레임워크가 자체적으로 생성하여 DB 연동을 처리한다. JPA는 Hibernate를 비롯한 모든 ORM의 공통 인터페이스를 제공하는 자바 표준 API이다.
Ibatis or Mybatis
Ibatis 프레임워크는 개발자가 작성한 SQL 명령어와 자바 객체(VO 혹은 DTO)를 매핑해주는 기능을 제공하며, 기존에 사용하던 SQL 명령어를 재사용하여 개발하는 차세대 프로젝트에 유용하게 적용할 수 있다. Mybatis는 Ibatis에서 파생된 프로임워크로서 기본 개념과 문법은 거의 같다.
POJO(Plain Old Java Object);
IoC(Inversion of Control); 제어의 역행. 느슨한 결합, 낮은 결합도
AOP(Aspect Oriented Programming); 관점지향 프로그래밍. 공통 로직을 분리하여 높은 응집도의 개발 지원
polymorphism 다형성
Design Patterns; Factory Pattern
스프링 설정 파일 생성; 프로젝트의 src/main/resources 소스 폴더 선택 → 컨텍스트 메뉴 [New] → [Other] → 'Spring' 폴더의 'Spring Bean Configuration File' 선택 <Next> → File name에 'applicationContext' 입력 <Finish>
...
<bean id="{id}" class="{class path}"/>
...
...
import org.springframework.context.support.AbstractAppicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
...
public class {class}
{
public static void main(String[] args)
{
// 1. Spring 컨테이너 구동
Abstract ApplicationContext factory = new GenericXmlApplicationContext("applicationContext.xml");
// 2. Spring 컨테이너로부터 필요한 객체를 요청(Lookup).
TV tv = (TV)factory.getBean("tv");
}
}
...
주로 변수 위에 설정하여 해당 타입의 객체를 찾아서 자동으로 할당한다.
org.springframework.beans.factory.annotation.Autowired
@Qualifier
특정 객체의 이름을 이용하여 의존성 주입할 때 사용한다.
org.springframework.beans.factory.annotation.Qualifier
@Inject
@Autowired와 동일한 기능을 제공한다.
javax.annotation.Resource
@Resource
@Autowired와 @qualifier의 기능을 결합한 어노테이션이다.
javax.inject.Inject
@Autowired; 변수 앞에
@Qualifier(“id”); 의존성 주입 대상이 두 개 이상일 때 @Autowired와 함께
@Resource(name=“id”);
어노테이션과 XML 설정 병행하여 사용
어노테이션
위치
의미
@Service
XXXXServiceImpl
비즈니스 로직을 처리하는 Service 클래스
@Repository
XXXDAO
데이터베이스 연동을 처리하는 DAO 클래스
@Controller
XXXController
사용자 요청을 제어하는 Controller 클래스
XxxVO, XxxDAO, XxxService, XxxServiceImpl
VO(Value Object) DTO(Data Transfer Object) 작성 데이터 전달 목적
DAO(Data Access Object) 데이터 베이스 연동
드라이버 다운로드; pom.xml <dependencies> 태그 안에 추가
JDBC Utility 클래스; Connection 획득 및 해제 작업
클래스 작성; @Repository(“boardDAO”), insert, update, delete, get, list 메서드 작성
Service 인터페이스 작성; DAO 클래스에서 <Alt> + <Shift> + <T>
Service 구현 클래스 작성;
@Service(“boardService”)
@Autowired로 DAO 연결
실행; 컨테이너 구동 → BoardServiceImpl 객체 Lookup → VO 객체 → insert/update/list,… → 컨테이너 종료
Spring AOP
IoC → 결합도, AOP(Aspect Oriented Programming) → 응집도
관심 분리 Separation of Concerns; 횡단 관심 Crosscutting Concerns, 핵심 관심 Core Concerns
AOP 라이브러리 추가; pom.xml → Maven Dependencies 확인 → 스프링 설정파일 applicationContext.xml에서 [Namespaces] 탭 → aop 네임스페이스 추가 → applicationContext.xml 에 <bean> 등록 → aop 관련 설정 추가
Aspect는 Pointcut과 advise의 결합으로서, 어떤 포인트컷 메소드에 대해서 어떤 어드바이스 메소드를 실행할지 결정
AOP 엘리먼트
<aop:config>; AOP 설정에서 루트 엘리먼트, 여러 번 사용가능, 하위에는 <aop:pointcut>, <aop:aspect> 엘리먼트가 올 수 있다
<aop:pointcut>; 포인트컷 지정을 위해 사용, <aop:config>나 <aop:aspect>의 자식 엘리먼트로 사용 가능, 여러 개 정의 가능, 유일한 아이디를 할당하여 애스팩트를 설정할 때 포인트컷을 참조하는 용도로 사용
<aop:aspect>; 핵심 관심에 해당하는 포인트컷 메소드와 횡단 관심에 해당하는 어드바이스 메소드를 결합하기 위해 사용
<aop:advisor>; 포인트컷과 어드바이스를결합한다는 점에서 애스팩트와 같은 기능, 하지만 트랜잭션 설정 같은 몇몇 특수한 경우는 애스팩트가 아닌 어드바이저를 사용해야 한다.
포인트컷 표현식
리턴타입 지정; 기본적인 방법은 *
패키지 지정; 패키지 경로 지정할 때는 *, .. 캐릭터 이용
클래스 지정; *, +
메소드 지정; 메소드 지정할 때는 주로 *, 매개변수를 지정할 때는 ..
매개변수 지정; .., *, 또는 정확한 타입 지정
리턴타입 지정
표현식
설명
*
모든 리턴타입 허용
void
리턴타입이 void인 메소드 선택
!void
리턴타입이 void가 아닌 메소드 선택
패키지 지정
표현식
설명
com.reth.biz
정확하게 com.reth.biz 패키지만 선택
com.reth.biz..
com.reth.biz 패키지로 시작하는 모든 패키지 선택
com.reth..impl
com.reth 패키지로 시작하면서 마지막 패키지 이름이 impl로 끝나는 패키지 선택
클래스 지정
표현식
설명
BoardServiceImpl
정확하게 BoardServiceImpl 클래스만 선택
*Impl
클래스 이름이 Impl로 끝나는 클래스만 선택
BoardService+
클래스 이름 뒤에 '+'가 붙으면 해당 클래스로부터 파생된 모든 자식 클래스 선택, 인터페이스 뒤에 '+'가 붙으면 해당 인터페이스를 구현한 모든 클래스 선택
메소드 지정
표현식
설명
*(..)
가장 기본 설정으로 모든 메소드 선택
get*(..)
메소드 이름이 get으로 시작하는 모든 메소드 선택
매개변수 지정
표현식
설명
(..)
가장 기본 설정으로서 '..'은 매개변수의 개수와 타입에 제약이 없음을 의미
(*)
반드시 1개의 매개변수를 가지는 메소드만 선택
(com.reth.user.UserVO)
매개변수로 UserVO를 가지는 메소드만 선택. 이때 클래스의 패키지 경로가 반드시 포함되어야 함
(!com.reth.user.userVO)
매개변수로 UserVO를 가지지 않는 메소드만 선택
(Integer, ..)
한 개 이상의 매개변수를 가지되, 천 번째 매개변수의 타입이 Integer인 메소드만 선택
(Interger, *)
반드시 두 개의 매개변수를 가지되, 첫 번째 매개변수의 타입이 Integer인 메소드만 선택
어드바이스 동작 시점
동작 시점
설명
Before
비즈니스 메소드 실행 전 동작
After
- After Returning: 비즈니스 메소드가 성공적으로 리턴되면 동작
- After Throwing: 비즈니스 메소드 실행 중 예외가 발생하면 동작(마치 try-catch 블록에서 catch 블록에 해당)
- After: 비즈니스 메소드가 실행된 수, 무조건 실행(try~catch~finally 블록에서 finally 블록에 해당)
Around
Around는 메소드 호출 자체를 가로채 비즈니스 실행 전후에 처리할 로직을 삽입할 수 있음
JoinPoint 메소드; 비즈니스 메소드 이름, 메소드가 속한 클래스와 패키지 정보를 알아야 할 때 사용
Client ↔ Container(JSP as a Controller + View, JavaBeans as a Model) ↔ DBMS
JSP 파일이 가장 중요 역할 수행; Controller + View 기능 처리 → 역할 구분이 명확하지 않음, JSP 파일에 대한 디버깅과 유지보수에 많은 어려움
Model 1 구조의 단점 보완 → Model 2 == MVC; Model, View, Controller
Model 2 아키텍처
Model 1 아키텍처는 엔터프라이즈 시스템에 부적합
Client ↔ Container(Servlet as a Controller, JSP as a View, JavaBeans as a Model) ↔ DBMS
Controller 구현
서블릿 생성 및 등록; 프로젝트 탐색창 src/main/java 컨텍스트 메뉴 → [New] → [Servlet] → Java Package에 com….view.controller, Class name에 DispatcherServlet 입력 → [Next] → Name에 action, URL mappings에 /action을 더블 클리하여 Pattern을 *.do로 설정 → [Finish] ⇒ DispatcherServlet 클래스가 만들어지는 순간 WEB-INF/web.xml 파일에 서블릿 관련 설정이 자동으로 추가됨. <description>, <display-name> 의미없는 설정이므로 제거
Controller 서블릿 구현; doGet(), doPost(), process(). doPost()에 한글 처리 인코딩 추가 request.setCharacterEncoding(“”); process()에서 분기 처리
MVC 프레임워크
Controller를 서블릿 클래스 하나로 구현하는 것은 DispatcherServlet 클래스가 복잡하게 구현되어 복잡도 증가 → 프레임워크의 Controller를 사용
Container
DispatcherServlet → HandlerMapping
DispatcherServlet → Controller
DispatcherServlet ← String ← Controller
DispatcherServlet → ViewResolver
클래스
기능
DispatcherServlet
유일한 서블릿 클래스로서 모든 클라이언트의 요청을 가장 먼저 처리하는 Front Controller
HandlerMapping
클라이언트의 요청을 처리할 Controller 매핑
Controller
실질적인 클라이언트의 요청 처리
ViewResolver
Controller가 리턴한 View 이름으로 실행될 JSP 경로 완성
MVC 프레임워크 구현
Controller 인터페이스 작성
Controller 구현체
HandlerMapping 클래스 작성
ViewResolver 클라스 작성
DispatcherServlet 수정
Spring MVC 구조
Client → (request) → DispatcherServlet
DispatcherServlet → HandlerMapping
DispatcherServlet → Controller
DispatcherServlet ← ModelAndView ← Controller
DispatcherServlet → ViewResolver
DispatcherServlet → View
클라이언트로부터의 모든 “.do” 요청을 DispatcherServlet이 받는다
DispatcherServlet은 HandlerMapping을 통해 요청을 치리할 Controller를 검색.
DispatcherServlet은 검색된 Controller를 실행하여 클라이언트의 요청을 처리.
Controller는 비즈니스 로직의 수행 결과로 얻어낸 Model 정보와 Model을 보여줄 View 정보를 ModelAndView 객체에 저장하여 리턴
DispatcherServlet은 ModelAndView로부터 View 정보를 추출하고, ViewResolver를 이용하여 응답으로 사용할 View를 얻어냄.
DispatcherServlet은 ViewResolver를 통해 찾아낸 View를 실행하여 응답 전송
DispatcherServlet 등록 및 스프링 컨테이너 구동
DispatcherServlet 등록; WEB-INF/web.xml
스프링 컨테이너 구동; DispatcherServlet.java
스프링 설정 파일 등록; 프로젝트 탐색창 WEB-INF 컨텍스트 메뉴 → [New] → [Other] → Spring 폴더에서 Spring Bean configuration file 선택 → [Next] → File name에 action-servlet.xml 파일 명입력 → [Finish] → 생성된 파일의 이름과 경로 확인
스프링 설정 파일 변경; WEB-INF 폴더 아래 config 폴더 생성 → 위에 생성한 파일 action-servlet.xml 파일 이동 → presentation-layer.xml로 이름 변경 → web.xml 파일 열고 DispatcherServlet 클래스 등록한 곳에 <init-param> 성정 추가
모든 Controller 클래스가 스캔 범위에 포함되도록 <context:componet-scan> 엘리먼트의 base-package 속성에 Controller 클래스들이 있는 가장 상위 패키지인 'com.reth.view'를 등록
또한, 어노테이션 활용에 집중하기 위해, 스프링 설정 파일에 등록한 ViewResolver 설정을 삭제. jsp파일의 위치도 원래대로 src/main/webapp 폴더 밑으로
@Controller
@Component를 상속한 @Controller는 @Controller가 붙은 클래스의 객체를 메모리에 생성하는 기능 제공. 단순히 객체를 생성하는 것에 그치지 않고, DispatcherServlet이 인식하는 Controller로 만들어 준다.
만일 @Controller를 사용하지 않는다면, 모든 컨트롤러 클래스는 반드시 스프링에서 제공하는 Controller 인터페이스를 구현해야 한다. 그리고 handleRequest() 메소드를 반드시 재정의하여 DispatcherServlet이 모든 Controller의 handleRequest() 메소드를 호출할 수 있도록 해야한다.
import org.springframework.stereotype.Controller;
@Controller
public class InsertBoardController
{
}
@ConditionalOnClass { Servlet.class, DispatcherServlet.class, WebMvcConfigurerAdapter.class }: 언급된 클래스 중 하나라도 클래스 패스에 있으면 자동 설정이 사용된다. 웹 스타터 프로젝트를 추가할 때 언급된 모든 클래스의 의존 관계를 가져온다. 그러면 자동 설정이 활성화된다.
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class): 자동 설정은 애플리케이션이 WebMvcConfigurationSupport.class 클래스의 빈을 명시적으로 선언하지 않은 경우에만 활성화된다.
@AutoConfigurerOrder(Ordered.HIGHEST_PRECEDENCE + 10): 특정 자동 설정의 우선순위를 지정한다.
@ConditionalOnBean(ViewResolver.class): ViewResolver.class가 클래스 패스에 있으면 빈을 생성한다.
@ConditionalOnMissingBean(name = “viewResolver”, value = ContentNegotiatingViewResolver.class): viewResolver 이름과 ContentNegotiatingViewResolver.class 유형의 명시적으로 선언된 빈이 없으면 이 빈을 생성한다.
나머지 메소드는 뷰 리졸버에서 구성된다
애플리케이션 구성 외부화
application.properties 시작
application.properties를 통한 프레임워크 사용자 정의
로깅 구성
임베디드 서버 구성 사용자 정의
스프링 MVC 설정
스프링 스타터 시큐리티 구성
데이터 소스, JDBC와 JPA 사용자 정의
기타 구성 옵션
애플리케이션별로 사용자 정의 속성 정의
구성 속성을 통한 타입세이프 구성관리
다른 환경에 프로파일 생성
액티브 프로파일을 기반으로 동적 빈 구성
애플리케이션 구성을 제공하기 위한 기타 옵션
YAML 구성
임베디드 서버
전통적인 자바 애플리케이션 배포; APP. WAR, 톰캣, 자바
임베디드 서버; 자바, ( (임베디드 톰캣), APP. WAR )
제티 및 언더토우 임베디드 서버
JAR를 사용하는 대신 기존 WAR 파일 빌드
개발자 도구를 사용해 생산성 향상
브라우저에서 실시간 리로드 활성화
애플리케이션 모니터링에 스프링 부트 액추에이터 사용
HAL 브라우저를 사용해 액추에이터 엔드포인트 찾기
애플리케이션 구성 속성
환경 세부 정보
애플리케이션 상태 모니터링
매핑 정보 얻기
빈 구성으로 디버깅
중요한 매트릭스 탐색
자동 설정의 디버그 정보 얻기
디버깅
스프링 프레임워크 심화
스프링과 AspectJ로 AOP 살펴보기
크로스 컷팅 및 AOP 탐색; 로깅, 시큐리티, 성능 추적
중요한 AOP 용어
어드바이스 advice
포인트컷 PointCut
포인트 컷 + 어드바이스 ⇒ 애스팩트 aspect
위빙 weaving
컴파일 타임 위빙 Compile-Time Weaving; 입력은 소스코드고 출력은 위빙이 있는 컴파일된 클래스
바이너리 위빙 Binary Weaving; 코드가 컴파일된 후에 수행. 입력은 컴파일된 클래스 파일 또는 jar 파일이고 출력은 위빙이 있는 컴파일된 클래스나 jar 파일이다.
런타임 위빙 Runtime Weaving; 위빙은 클래스가 JVM에 로드되기 직전에 수행된다.
AOP 프레임워크; AspectJ → 컴파일 타임 위빙
AOP 실습; spring-boot-starter-aop → 비즈니스 시나리오 설정 → 포인트컷 식별 → aspect 정의; 인터셉션 포인트
@Before; 메소드를 실행하기 전
@After; 메소드 실행 후. 메소드가 예외를 발생시키더라도 실행
@AfterReturning; 메소드가 성공적으로 실행된 후
@AfterThrowing; 메소드 호출 후 예외가 발생했다
@Around; 메소드 실행을 완전히 제어
사용자 정의 AOP 어노테이션 정의;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogEverything {
}
@LogEverything
public void placeOrder(int value) {
스프링으로 작업 스케줄링하기
@Scheduled로 작업 스케줄링 하기
@Async를 사용해 비동기식으로 작업 실행하기 → @Async 메소드에서 값 반환하기
작업 실행자 executor
스프링 프레임워크를 이용한 스크립팅
JSR 233 - 자바TM 플랫폼용 스크립팅
자바로 자바스크립트 코드 실행하기
자바에서 그루비 코드 실행하기
스프링 엔터프라이즈 애플리케이션에서 그루비 코드 실항하기; 그루비 코드를 스프링 컨텍스트 XML로 인라이닝하기
스프링 부트의 REST API
SOAP (Simple object Access Protocol)를 사용하는 XML 기반 → REST
REST (Representational State Transfer)
서버 Server; 서비스 공급자. 클라이언트에게 서비스를 제공
클라이언트 Client; 서비스 소비자. 브라우저 또는 다른 시스템일 수 있다.
리소스 Resource; 모든 정보는 리소스가 될수 있다(사람, 이미지, 비디오 또는 판매하는 제품 등)
리프리젠테이션 Representation; 리소스를 표현하는 구체적인 방법. 예를 들어 JSON, XML 나 HTML을 통해 제품 리소스를 나타낼 수 있다. 클라이언트마다 리소스의 다른 표현을 요청할 수 있다.
REST 제약 조건
클라이언트-서버 Client-server; 서버(서비스 공급자)와 클라이언트(서비스 소비자)가 있어야 한다. 새로운 기술이 등장함에 따라 서버와 클라이언트의 느슨한 결합과 독립적 진화를 가능하게 한다
무상태 Stateless; 각 서비스는 무상태여야 한다. 후속 요청은 일시적으로 저장되는 이전 요청의 일부 데이터에 의존하면 안 된다. 메시지는 스스로 설명할 수 있어야 한다.
통일된 인터페이스 Uniform interface; 각 리소스에는 리소스 식별자가 있다. 웹 서비스의 경우, URI(Uniform Resource Identifier) 예제인 /users/Jack/todos/1을 사용한다. 여리서 URI Jack은 사용자 이름이고 1은 검색하려는 todo의 ID다.
캐시 가능 Cacheable; 서비스 응답은 캐시가 가능해야 한다. 각 응답은 캐시 가능한지 여부를 표시해야 한다.
레이어 시스템 Layered system; 서비스 소비자는 서비스 공급자와 지접 연결돼서는 안 된다. 요청을 캐시할 수 있으므로 클라이언트는 중간 레이어에서 캐시된 응답을 가져올 수 있다.
리프리젠테이션을 통한 리소스 연산; 리소스는 여러 리프리젠테이션을 가질 수 있다. 리프리젠테이션이 포함된 메시지로 리소스를 수정할 수 있어야 한다.
HATEOAS; RESTful 애플리케이션의 소비자는 하나의 고정 서비스 URL만을 알아야 한다. 모든 후속 리소스는 리소스 표현에 포함된 링크에서 검색할 수 있어야 한다.
첫 번째 REST API 설계
REST API 연산을 위한 요청 메소드 및 URI 결정
HTTP 요청 메소드
HTTP 요청 메소드
오퍼레이션
GET
읽기 - 리소스의 세부 정보 검색
POST
생성 - 새로운 아이템 또는 리소스 생성
PUT
업데이트/교체
PATCH
리소스 일부 업데이트/수정
DELETE
삭제
스프링 부트로 Hello World API 만들기
Rest Controller
@RestController; @RestController 어노테이션은 @ResponseBody와 @Controller 어노테이션의 조합을 제공. 일반적으로 REST 컨트롤러를 생성하는 데 사용
@GetMapping(“welcome”); @GetMapping은 @RequestMapping(method = RequestMethod.GET)의 바로가기이다. 어노테이션이 있는 메소드는 welcome URI의 GET 요청을 처리한다
@AssertFalse, @AssertTrue: 부울 Boolean 요소이면 어노테이션이 달린 요소를 획인
@AssertFalse: false를 확인
@Assert: true를 확인
@Future: 어노테이션이 달린 요소는 미래의 날짜여야 한다
@Past: 어노테이션이 달린 요소는 과거의 날짜여야 한다.
@Max: 어노테이션이 달린 요소는 값이 지정된 최대 값보다 작거나 같은 숫자여야 한다
@Min: 어노테이션이 달린 요소는 지정된 최솟값보다 크거나 같은 숫자여야 한다.
@NotNull: 어노테이션이 달린 요소는 null일 수 없다.
@Pattern: 어노테이션이 달린 {@code CharSequence} 요소는 지정된 정규 표현식과 일치해야 한다. 정규 표현식은 자바 정규 표현식 규칙을 따른다.
@Size: 어노테이션이 달린 요소 크기는 지정된 범위에 있어야 한다.
OpenAPI 스펙을 사용한 REST 서비스 문서화
스웨거 스펙 생성
@Configuration: 스프링 설정 파일을 정의
@EnableSwagger2: 스웨거 지원을 위한 어노테이션
Docket: 스웨거 스프링 MVC 프레임워크를 사용해 스웨거 문서 생성을 구성하는 간단한 빌더 클래스
new Docket(DocumentationType.SWAGGER_2): 스웨거2를 사용할 스웨거 버전으로 구성
.apis(RequestHandlerSelectors.any()) .paths(PathSelectors.any()): 문서의 모든 API와 경로를 포함한다
스웨거 스펙 살펴보기; 스웨거 UI를 사용해 스웨거 문서 탐색하기, 어노테이션을 사용한 커스텀 스웨거 문서
@ApiOperation(value = “Retrieve all todos for a user by passing in his name”): 서비스 요약으로 문서에 생성된다.
notes = “A list of matching todos is returned. Current pagination is not supported.”: 서비스를 설명한 내용으로 문서에 생성된다
produce = “application/json”: 서비스 문서의 produce 섹션을 커스텀한다
@Api: 클래스를 스웨어 리소스로 표시
@ApiModel: 스웨거 모델의 추가 정보를 제공
@ApiModelProperty: 모델 속성의 데이터를 추가하고 조작
@ApiOperation: 특정 경로의 오퍼레이션이나 HTTP 메소드를 설명
@ApiParam: 오퍼레이션 파라미터에 추가 메타 데이터를 추가
@ApiResponse: 오퍼레이션 응답 예를 설명
@ApiResponses: 여러 ApiResponse 객체 리스트를 허용하는 래퍼
@Authorization: 리소스나 오퍼레이션에 사용되는 권한 부여 체계를 선언
@AurhorizationScope: OAuth2 인증 범위를 설명
@ResponseHeader: 응답의 일부로 제공될 수 있는 헤더를 나타낸다
@SwaggerDefinition: 생성된 스웨거 정의에 추가할 정의 레벨 속성
@Info: 스웨거 정의의 일반 메타 데이터
@Contact: 스웨거 정의를 위해 연락할 사람을 설명하는 속성
@License: 스웨거 정의의 라이센스를 설명하는 속성
REST API 국제화 구현
LocaleResolver와 메시지 소스 추가
sessionLocaleResolver.setDefaultLocale(Locale.US): 기본 지역으로 Locale.US를 설정
messasgeSource.setBasenames(“message”): 메시지 소스의 기본 이름을 message로 설정. fr 지역(프랑스)에 있다면 message_fr.properties의 메시지를 사용. message_fr.properties에서 메시지를 사용할 수 없으면 기본 message.properties에서 검색
messageSource.setUseCodeAsDefaultMessage(true): 메시지를 찾지 못하면 코드는 기본 메시지를 반환
@RequestHeader(value = “Accept-Language”, required = false) Locale locale: 지역은 요청 헤어 Accept-Language에서 선택된다. 필수는 아니다. 지역을 지정하지 않으면 기본 지역이 사용된다.
messageSource.getMessage(“welcome.message”, null, locale): 따라서 messageSource는 컨트롤러에 자동 연결된다. 주어진 지역에 따라 welcome 메시지를 받는다
REST API 캐싱 구현
caching-spring-boot-starter-cache를 위한 스타터 프로젝트
애플리케이션의 캐싱 활성화; @EnableCaching
데이터 캐싱; @Cacheable(”..“)
@CachePut; 데이터를 캐시에 명시적으로 추가하는 데 사용
@CacheEvict; 캐시에서 오래된 데이터를 제거하는 데 사용
@Caching; 여러 개의 중첩된 @Cacheable, @CachePut, @CacheEvict 어노테이션을 같은 메소드에서 사용할 수 있다.
JSR-107 캐싱 어노테이션
@CacheResult; @Cacheable과 비슷하다
@CahceRemove; @CacheEvict와 유사하다. @CahceRemove는 예외가 발생하면 조건부 제거를 지원한다.
@CacheRemoveAll; @CacheEvict(allEntries=true)와 유사하게 캐시에서 모든 항목을 제거하는 데 사용
클라우드에 스프링 부트 애플리케이션 배포; 클라우드 파운드리 Cloud Foundry, 헤로쿠 Heroku, 오픈시프트 OpenShift, 아마존 웹 서비스 AWS
스프링 부트의 REST API 단위 테스트
스프링 부트를 이용한 REST API 단위 테스트
스프링 부트 스타터 테스트에 의존 관계 추가
JUnit: 가장 널리 사용되는 자바 단위 테스트 프레임워크는 단위 테스트 작성을 위한 기본 구조를 제공한다
스프링 테스트(spring-test): 스프링 컨텍스트를 시작하기 위해 단위 테스트를 작성하는 기능을 제공한다. REST API를 단위 테스트하는 데 사용할 수 있는 모크 MVC 프레임워크도 제공한다
모키토 코어(mockito-core): 모크로 단위 테스트를 작성하는 데 도움이 된다
AssertJ 코어(assertj-core): 간단하고 읽기 쉬운 어설션을 작성할 수 있다. 예를 들면 assertThat(nubersList).hasSize(15).contains(1, 2, 3).allMatch(x → x < 100)이다
Hamcrest 코어(hamcrest-core): 훌륭한 어설션을 작성하는 또 다른 프레임워크다. 예를 들면 assertThat(“XYZ”, containsString(“XY”))이다
JSON Path(json-path): XML용 XPath와 유사하게 JSONPath로 JSON 응답의 요소를 식별하고 단위 테스트를 할 수 있다
JSON Assert(JSONAssert): JSON Assert를 사용하면 예상되는 JSON을 지정하고 이를 사용해 JSON 응답의 특정요소를 체크할 수 있다.
BasicController API 단위 테스트
기본 단위 테스트 설정
@RunWith(SpringRunner.class): SpringRunner는 SpringJUnit4ClassRunner 클래스의 바로가기다. 단위 테스트를 위한 간단한 스프링 컨텍스트를 시작한다
@WebMvcTest(BasicController.class): 어노테이션을 SpringRunner와 함께 사용해 스프링 MVC 컨트롤러에 간단한 테스트를 작성할 수 있다. 스프링 MVC 관련 어노테이션으로 어노테이션이 달린 빈만 로드한다. 예제에서는 BasicController 클래스를 테스트하면서 웹 MVC 테스트를 컨텍스트를 시작한다
@Autowired private MockMvc mvc: 요청하는 데 사용할 수 있는 MockMvc 빈을 자동 연결한다
secure = false: 단위 테스트에서 시큐리티를 사용하고 싶지 않을 수도 있다. WebMvcTest 어노테이션의 secure = false 매개변수는 단위 테스트에 스프링 시큐리티를 사용하지 않는다
문자열을 반환하는 Hello World API의 단위 테스트 작성하기
mvc.perform(MockMvcRequestBuilders.get(”/welcome“).accept(MediaType.APPLICATION_JSON)): Accept 헤더 값, application/json을 사용해 /welcome의 요청을 수행한다
andExpect(status().isOK()): 응답 상태는 200(success)다
andExpect(content().string(equalTo(“Hello World”))): 응답 내용이 “Hello World”와 같을 것으로 예상한다
JSON을 반환하는 Hello World API의 단위 테스트 작성하기
경로 매개변수를 사용해 Hello World API의 단위 테스트 작성하기
TodoController API의 단위 테스트
TodoController API의 단위 테스트 설정
모든 todo를 검색하기 위한 단위 테스트 작성 - GET 메소드
특정 todo를 검색하기 위한 단위 테스트 작성 - GET 메소드
todo 생성을 위한 단위 테스트 작성 - POST 메소드
유효성 검사 오류가 있는 todo를 생성하기 위한 단위 테스트 작성
todo 업데이트를 위한 단위 테스트 작성 - PUT 메소드
todo 삭제를 위한 단위 테스트 장성 - DELETE 메소드
스프링 부트와 REST API 통합 테스트
BasicController의 통합 테스트 작성
MOCK: 모크 웹 환경에서 컨트롤러를 단위 테스트한다. 앞에서 단위 테스트에서 한 것과 유사하다
RANDOM_PORT: 사용 가능한 랜덤 포트의 임베디드 서버에서 다른 레이어를 포함한 전체 웹 컨텍스트를 시작한다
DEFINED_PORT: 포트 번호를 하드 코딩한다는 점을 제외하고 RANDOM_PORT와 유사하다
NONE: 웹 컨텍스트 없이 스프링 컨텍스트를 로드한다
문자열을 반환하는 Hello World API의 통합 테스트 작성 → JSON을 반환하는 Hello World API의 통합 테스트 작성 → 경로 매개변수를 사용해 Hello World API의 통합 테스트 작성
TodoController API의 통합 테스트
Todo API 통합 테스트 설정
모든 todo를 검색하기 위한 통합 테스트 작성 - GET 메소드
todo를 만들기 위한 통합 테스트 작성 - POST 메소드
todo 업데이트를 위한 통합 테스트 작성 - PUT 메소드
todo 삭제를 위한 통합 테스트 작성 - DELETE 메소드
단위 및 통합 테스트 모범 사례
단순한 디자인의 4가지 원칙 4 Principles of Simple Design
모든 테스트로 실행한다: 단위 테스트는 소스코드와 함께 지속적으로 작성되며 통합된다
중복 포함을 최소화한다: 코드에는 가능한 한 중복을 최소화한다
프로그래머의 의도를 표현한다: 코드는 이해하기 쉬워야 한다. 테스트에서 중요한 값을 명확하게 강조해 쉽게 읽을 수 있게 하고, 테스트에 좋은 메소드 이름을 지정한다. Hamcrest Matchers, AssertJ 및 JSON Path와 같은 프레임워크를 사용하 훌륭한 어설션을 작성해보자
클래스 및 메소드 수를 최소화한다: 관련된 각 요소(메소드, 클래스, 패키지, 구성요소 및 애플리케이션)는 가능한 한 최소로 한다. 테스트당 조건을 하나만 작성해 단위 테스트를 작게 유지할 수 있다. 또한 단위 테스트의 범위도 가능한 작게 유지한다(일반적으로 최대의 메소드는 메소드 그룹이다)
단위 테스트와 관련된 모범 사례
프로덕션 코드에 문제가 있는 경우에만 테스트가 실패한다: 데이터베이스의 데이터 변경과 같은 외부 의존 관계로 인해 테스트가 실패하면 개발팀은 테스트에 신뢰를 잃게 된다. 일정 시간 지나면 테스트가 부패하고 팀은 테스트 실패를 무시하기 시작한다
테스트는 프로덕션 코드와 관련된 모든 중요한 문제를 찾아야 한다: 예외를 포함한 모든 가능 시나리오에 단위 테스트를 시도하고 작성해보자
테스트는 빠르게 실행돼야 한다: 테스트는 빠르게 실행해야 한다. 개발자는 테스트를 자주 실행하는 경향이 있다. 지속적인 통합 빌드가 빠르게 실행되고 개발자는 빠른 피드백을 받을 수 있다. 단위 테스트에서 스프링 컨텍스트를 시작하지 않고 모크로 단위 테스트를 실행하는 것을 선호한다
테스트는 가능한 한 자주 실행한다: 지속적으로 통합 테스트를 실행해보자. 코드가 버전 컨트롤에 들어가자마자 빌드가 트리거되고 테스트가 실행된다. 이를 통해 팀이 작성하는 훌륭한 단위 테스트를 최대한 활용할 수 있다.
스프링 시큐리티를 활용한 REST API
스프링 시큐리티를 이용한 시큐리티 REST API
REST API 시큐리티
인증authentication - 유효한 사용자인가?
권한부여authorization - 유효한 사용자가 작업을 수행할 수 있는가?
REST API 시큐리티 구현
REST API 요정은 URL, 요청 데이터와 사용자 자격 증명 정보를 제공받이 실행된다.
필터가 인증을 확인한다(유효한 사용자?). 일반적으로 사용자 ID/암호 조합 또는 토큰이 자격 증명으로 사용된다. 그후 필터는 권한을 검사한다(사용자에게 올바른 권한이 있는가?)
REST API 요청이 실행된다.
스프링 시큐리티 추가하기
스프링 시큐리티 스타터 추가
스프링 부트 스타터 시큐리티 의존관계
스프링 부트 스타터 시큐리티 자동 설정
기본 인증 자격 증명으로 통합 테스트 업데이트
시큐리티를 비활성화하기 위해 단위 테스트 업데이트
스프링 시큐리티
로그 검토
스프링 시큐리티 필터
UsernamePasswordAuthenticationFilter: 사용자 자격 증명을 사용해 인증한다. 요청이 POST고 사용자 자격 증명이 있는 경우 실행된다.
BasicAuthenticationFilter: 기본 인증한다. 요청에 기본 인증 요청 헤더가 있는 경우 실행된다.
AnonymousAuthenticationFilter: 요청에 인증 자격 증명이 없으면 익명 사용자가 생성된다. 일반적으로 익명 사용자는 인증이 필요 없는 API인 퍼블릭 API의 요청을 실행할 수 있다.
ExceptionTranslationFilter: 추가 시큐리티를 제공하지 않는다. 인증 예외를 적절한 HTTP 응답으로 변환한다.
FilterSecurityInterceptor: 인증을 결정한다
HeaderWriterFilter: 시큐리티 헤더를 응답에 기록한다(X-FrameOptions, X-XSS-Protection 및 X-Content-Type-Options).
CsrfFilter: CSRF 보호를 확인한다.
스프링 시큐리티의 인증
인증 매니저
ProviderManager
AuthenticationProvider
UserDetailsService 구현하기
UserDetailsManager로 사용자 관리하기
스프링 시큐리티의 인증 확장 포인트
UserDetailsService의 커스텀 구현 제공
글로벌 인증 매니저 구성을 위한 웹 시큐리티 구성 프로그램 어댑터 확장
웹 시큐리티 구성 어댑터를 사용한 시큐리티 구성
스프링 시큐리티의 권한
access decision manager를 사용한 권한 부여
스프링 시큐리티의 인증 확장 포인트
웹 시큐리티 구성 어댑터를 사용한 HTTP 시큐리티 구성
서비스 메소드에 시큐리티 어노테이션 제공
서비스 메소드에 JSR-250 어노테이션 제공
스프링 시큐리티 pre 어노테이션과 post 어노테이션
스프링 시큐리티를 이용한 시큐리티 모범 사례 구현
CSRF 공격을 방지한다
세션 고정 문제로부터 보호한다
응답에 헤더를 자동으로 추가해 시큐리티를 강화한다
요청이 HTTP인 경우 엄격한 HTTP 전송 시큐리티를 지정한다
캐시 컨트롤 헤더를 추가한다
cross-site protection 헤더를 추가한다
X-Frame-Options 헤더를 추가해 클릭 재킹을 방지한다
OAuth2 인증
OAuth는 다양한 웹 지원 애플리케이션과 서비스 사이의 권한 및 인증 정보를 교환하기 위해 플로우를 제공하는 프로토콜
일반적인 OAuth2 교환에서 중요한 플레이어
리소스 소유자: 리소스 소유자는 Todo API의 사용자인 데이터 소유자다. 리소스 소유자는 API로 제공되는 정보 중 타사 애플리케이션에 제공할 수 있는 정보의 양을 결정한다
리소스 서버: Todo API에 액세스가 제공되는 실제 리소스다
클라이언트: Todo API 애플리케이션과 통합하려는 타사 애플리케이션이다.
인증서버: OAuth 서비스를 제공하는 서버다
클라이언트 자격 증명: 각 타사 애플리케이이션에는 자신을 OAuth 사버에 식별하는 자격 증명이 있다. 이를 클라이언트 자격 증명이라고 한다
OAuth2 상위 플로우
권한 부여 플로우
리소스 액세스 플로우
OAuth2 서버 생성
인증 서버 설정: REST API에 사용자 자격 증명 설정 → 타사 클라이언트 자격 증명으로 인증 서버 설정 액세스 토큰 얻기 → 리소스 서버 설정 → 액세스 토큰을 사용해 요청 실행 → 통합 테스트 업데이트
access_token: 클라이언트 애플리케이션은 액세스 토큰을 사용해 추가 API 호출을 인증할 수 있다. 그러나 액세스 토큰은 일반적으로 매우 짧은 기간 안에 만료된다.
refresh_token: 클라이언트 애플리케이션은 refresh_token을 사용해 인증 서버에 새로운 요청을 제출해 새로운 access_token을 얻을 수 있다.
JWT를 이용한 인증
JWT; JWT 토큰은 사용자 세부사항, 사용자 권한 부여 및 몇 가지 커스텀 애플리케이션 특정 세부사항을 포함하는 암호화된 토큰이다.
대용량; 일반적으로 기존의 데이터베이스(예: 로그 스트림, 페이스북 게시물 및 트윗)에서 처리할 수 있는 것보다 용량이 많다
쉽게 확장 가능; 일반적으로 수평 및 수직으로 확장할 수 있는 옵션을 제공한다
관계형 데이터베이스와 통신
마이바티스 myBatis(기존 아이바티스 iBatis); 마이바티스는 매개변수를 설정하고 결과를 검색하기 위해 코드를 수동으로 작성할 필요가 없다. 자바 POJO를 데이터베이스에 매핑하는 간단한 XML이나 어노테이션 기반 구성을 제공한다.
하이버네이트 Hibernate; 하이버네이트는 ORM(오브젝트/관계형 매핑) 프레임워크다. ORM 프레임워크는 오브젝트를 관계형 데이터베이스의 테이블에 매핑하는 데 유용하다. 하이버네이트의 가장 큰 장점은 개발자가 직접 쿼리를 작성할 필요가 없다는 것이다. 객체와 테이블 간의 관계가 매핑되면 하이버네이트는 매핑을 사용해 쿼리를 생성하고 데이터를 채우거나 검색한다.
스프링 데이터
기능
다양한 레파지토리를 통해 여러 데이터 레파지토리와 쉽게 통합
레파지토리 메소드 이름을 기반으로 쿼리를 구문 분석하고 구성하는 기능
기본 CRUD 기능 제공
사용자가 생성한 후 마지막으로 변경된 경우와 같은 감사의 기본 지원
스프링과 강력한 통합
스프링 데이터 레스트 Spring Data Rest를 통해 REST 컨트롤러를 노출시키는 스프링 MVC와 통합
중요 스프링 데이터 모듈
스프링 데이터 커먼즈 Spring Data Commons: 모든 스프링 데이터 모듈에 공통 개념을 정의한다(레파지토리 및 쿼리 메소드)
스프링 데이터 JPA Spring Data JPA: JPA 레파지토리와 쉽게 통합한다
스프링 데이터 몽고DB Spring Data MongoDB: 문서 기반 데이터 레파지토리인 몽고DB와 쉽게 통합한다
스프링 데이터 REST Spring Data REST: 스프링 데이터 레파지토리를 최소한의 코드로 구성된 REST 서비스로 노출하는 기능을 제공한다
아파치 카산드라용 스프링 데이터 Spring Data for Apache Cassandra: 카산드라와 쉬운 통합을 제공한다
아파치 하둡용 스프링 Spring for Apache Hadoop: 하둡과 쉬운 통합을 제공한다
스프링 데이터 커먼즈; 레파지토리 인터페이스, CrudRepository 인터페이스, PagingAndSortingRepository 인터페이스
스프링 데이터 JPA를 사용해 관계형 데이터베이스에 연결
스프링 데이터 JPA 예제
스타터 데이터 JPA로 새 프로젝트 만들기
엔티티 정의하기
@Entity; 해당 클래스가 엔티티임을 지정하는 어노테이션
@Id는 ID가 엔티티의 기본 키임을 지정
@GeneratedValue(strategy = GenerationType.AUTO): GeneratedValue 어노테이션은 기본 키 생성 방법을 지정하는 데 사용된다. 예에서는 GenerationType.AUTO 전략을 사용하고 있다. 퍼시스턴스 공급자가 올바른 전략을 선택하기를 원한다는 것을 나타낸다
@ManyToOne(fetch - FetchType.LAZY)는 User와 Todo 사이의 다대일 관계를 나타낸다. 관계의 한쪽에서 @MayToOne 관계가 사용된다. FetchType.Lazy는 데이터를 느리가 가져올 수 있음을 나타낸다
@JoinColumn(name = “userid”): JoinColumn 어노테이션은 외래 키 열의 이름을 지정한다
SpringBootApplication 클래스 생성하기
일부 데이터 채우기
간단한 레파지토리 만들기
단위 테스트
@DataJpaTest: @DataJpaTest 어노테이션은 일반적으로 JPA 레파지토리 단위 테스트에서 SpringRunner와 함께 사용된다. @DataJpaTest 어노테이션은 JPA 관련 자동 설정만 활성화한다. 테스트는 기본적으로 인메모리 데이터베이스를 사용한다.
@RunWith(SpringRunner.class): SpringRunner는 SpringJUnit4ClassRunner의 간단한 별칭이다. 스프링 컨텍스트를 시작한다
@Autowired TodoRepository todoRepository: 테스트에 사용될 TodoRepository를 오토와이어링한다.
assertEquals(3, todoRepository.count()): 반환된 카운트가 3인지 확인한다. data.sql에 3개의 todo를 삽입했다는 것을 기억하자.
CrudRepository 인터페이스를 확장하는 레파지토리 생성하기
단위 테스트를 사용한 테스트
PagingAndSortingRepository 인터페이스를 확장하는 레파지토리 생성하기
단위 테스트를 이용한 탐색하기
커스텀 쿼리 메소드 작성하기
커스텀 JPQL 쿼리 작성하기
명명된 매개변수 사용
명명된 쿼리 사용
네이티브 SQL 쿼리 실행하기
거래 관리 시작
스프링 @Transactional 어노테이션
트랜잭션을 위한 스프링 부트 자동 설정
스프링 데이터를 이용한 몽고DB와의 상호 작용
스프링 데이터 몽고DB의 의존 관계 설정
Person 엔티티 생성
Person 레파지토리 생성
좋은지 확인하기 위해 단위 테스트 작성
스프링 데이터 REST를 사용해 REST API 생성하기
중요 기능
스프링 데이터 레파지토리를 중심으로 REST API를 노출한다
페이지 매김 기능과 필터링을 지원한다
스프링 데이터 레파지토리의 쿼리 메소드를 이해하고 이를 검색 리소스로 노출한다
지원되는 프레임워크 중에는 JPA, 몽고DB, 카산드라가 있다
리소스를 커스텀하는 옵션이 기본적으로 표시된다
GET 메소드
POST 메소드
검색 리소스
마이크로 서비스
애플리케이션 개발 목표; 애플리케이션을 개발할 때 필요한 공통 목표를 이해해야 마이크로서비스 아키텍처로 이동하는 이유를 이해하는 데 도움
빠른 애플리케이션 구축 - 속도
기술과 비즈니스 환경의 중요한 변화
새로운 프로그래밍 언어;
고 Go,
스칼라 Scala,
클로저 Closure,…
새로운 프로그래밍 패러다임;
함수형 프로그래밍,
리액티브 프로그래밍
새로운 프레임워크
새로운 도구
개발
코드 품질
자동화 테스트
배포
컨테이너화
새로운 프로세스 및 사례
애자일 Agile
테스트 중심 개발
행동 중심 개발
지속적인 통합
지속적인 배포
데브옵스 DevOps
새로운 장치 및 기회
모바일
클라우드
신뢰할 수 있는 애플리케이션 구축 - 안전
신뢰성 - 애플리케이션이 예상대로 작동할까?
가용성 - 애플리케이션을 항상 사용할 수 있을까?
안전성 - 애플리케이션은 안전한가?
성능 - 애프리케이션이 충분히 빠른가?
높은 복원력 - 애플리케이션이 실패에 잘 반응할까?
확장성 - 애플리케이션 로딩이 급격히 증가할 때 무엇을 지원해야 할까?
모놀리식 애플리케이션 문제
모놀리식 애플리케이션 특징
큰 크기: 대부분의 모놀리식 애플리케이션에는 코드 베이스가 많다
대규모 팀: 팀 규모는 20명에서 300명까지 다양하다
같은 일을 하는 여러 가지 방법: 팀 규모가 큰 탓에 의사소통에 차이가 있다. 그 결과 애플리케이션의 다른 부분에서 같은 문제의 솔루션이 여러 개 생성된다.
자동화 테스트 부족: 대부분 애플리케이션에는 단위 테스트가 거의 없으며 통합 테스트가 완벽하지 않다. 애플리케이션은 수동 테스트에 크게 의존한다
릴리스 업데이트의 문제 - 긴 릴리스 주기
확장의 어려움
새로운 기술에 적응의 어려움
새로운 방법론 적용의 어려움
현대적인 개발 사례 적용의 어려움; TDD Test-driven development, BDD behavior-driven development
마이크로서비스 시작
“많은 조직에서는 세밀한 마이크로서비스 아케텍처를 채택함으로써 소프트웨어를 좀더 빠르게 제공하고 새로운 기술을 도입할 수 있다는 것을 발견했다” - 샘 뉴먼, '마이크로서비스 구축'
“마이크로서비스는 함께 작동하는 소규모 자율 서비스다.” - 샘 뉴먼, 소트웍스
“제한된 컨텍스트를 사용해 느슨하게 결합된 서비스 지향 아키텍처다.” - 아드리안 콕크로프트, 배터리 벤처
마이크로서비스 아키텍처의 큰 그림
마이크로서비스 특성; 높은 코드 품질, 스몰, 경량, 메시지 기반, 무상태, 싱글 비즈니스 능력, 독립 팀, 독립 배포, 자동 빌드 릴리스, 이벤트 주도
작고 가벼운 마이크로서비스
메시지 기반 커뮤니케이션과의 상호 운용성
용량 할당 마이크로서비스
독립적으로 배포 가능한 마이크로서비스
무상태 마이크로서비스
완전 자동화된 빌드 및 릴리스 프로세스
이벤트 주도 아키텍처 준수
접근법
순차적 접근법
이벤트 주도 접근법
마이크로서비스 개발 및 지원을 위한 독립 팀 - 데브옵스
마이크로서비스 아키텍처의 장점
출시 시간 단축
기술 진화에 빠른 적응
확장성
현재 개발 방법론과의 호환성
마이크로서비스 문제
자동화의 필요성 증가
서브 시스템의 경계 정의
가시성 및 모니터링 필요성 증가
내결함성 증가
마이크로서비스 간 일관성 유지
표준화된 공유 기능 구축(엔터프라이즈 레벨)
하드웨어: 어떤 하드웨어를 사용하는가? 클라우드를 사용하는가?
코드 관리: 어떤 버전 관리 시스템을 사용하는가? 분기 및 커밋 코드의 관행은 무엇인가?
구축 및 배포: 어떻게 구축할까? 배포를 자동화하려면 어떤 도구를 사용하는가?
데이터 레파지토리: 어떤 종류의 데이터 레파지토리를 사용하는가?
서비스 오케스트레이션 orchestration: 서비스를 어떻게 조율하는가? 아떤 종류의 메시지 브로커를 사용하는가?
시큐리티 및 ID: 사용자 및 서비스를 인증하고 승인하는 방법은 무엇인가?
시스템 가시성 및 모니터링: 서비스를 어떻게 모니터링하는가? 시스템 전체에서 결함 격리를 어떻게 제공하는가?
운영팀의 필요성 증가
클라우드 네이티브 애플리케이션
12 팩터 앱 Twelve-Factor
하나의 코드 베이스 유지
명시적 의존 관계 선언
환경 설정
모든 의존 관계는 백엔드 서비스로 취급된다
빌드, 릴리스, 실행 단계를 명확하게 분리한다
빌드: 코드에서 실행 가능한 번들(EAR, WAR, JAR)과 여러 환경에 배포할 수 있는 의존 관계를 만든다
릴리스: 실행 가능한 번들을 특정 환경 설정과 결합해 배포한다
실행: 특정 릴리스를 사용해 실행 환경에서 앱을 실행한다.
애플리케이션은 상태를 저장하지 않는다 - 무상태
모든 서비스는 포트 바인딩으로 노출된다
수평 확장 가능성 - 동시성
각 애플리케이션 인스턴스는 일회용이다
환경 평가 - 모든 환경이 같아야 한다
모든 로그를 이벤트 스트림을로 취급한다
관리자 프로세스에 구별이 없다
마이크로서비스를 위한 스프링 프로젝트
스프링 부트
스프링 클라우드
구성관리: '12 팩터 앱'에서 설명한 것처럼 구성 관리는 클라우드 애플리케이션 개발의 중요한 부분이다. 스프링 클라우드느 마이크로서비스를 위한 중앙 집중식 구성 관리 솔루션인 스프링 클라우드 컨피그를 제공한다
서비스 디스커버리: 서비스 디스커버리는 서비스 간 느슨한 연결을 촉진한다. 스프링 클라우드는 유레카, 주키퍼, 콘솔과 같이 인기있는 서비스 디스커버리 옵션과 통합된다
서킷 브레이커: 클라우드 네이티브 애플리케이션은 내결함성이 있어야 하고, 서비스를 정상적으로 지원하지 못하는 문제를 처리할 수 있어야 한다. 서킷 브레이커는 장애 발생 시 최소한의 기본 서비스를 제공하는 데 중요한 역할을 한다. 스프링 클라우드는 넷플릭스 히스트릭스 내결함성 라이브러리와의 통합을 제공한다
API 게이트웨이: API 게이트웨이는 중앙 집중식 집계, 라우팅, 캐싱 서비스를 제공한다. 스프링 클라우는 API 게이트웨이 라이브러리인 넷플릭스 주울Zuul과의 통합을 제공한다
중요 스프링 클라우드 하위 프로젝트
스프링 클라우드 넷플릭스 Spring Cloud Netflix: 넷플릭스는 마이크로서비스 아케텍처의 초기 채택자 중 하나다. 많은 내부 넷플릭스 프로젝트가 스프링 클라우드 넷플릭스의 범위의 오픈소스로 제공됐다. 유레카, 히스트릭스 Hystrix와 주울을 예로 들 수 있다
스프링 클라우드 컨피그 Spring Cloud Config: 다양한 환경의 여러 마이크로서비스에서 중앙 집중식 외부 구성이 가능하다
스프링 클라우드 버스 Spring Cloud Bus: 간단한 메시지 브로커와 마이크로서비스 통합을 보다 쉽게 구축할 수 있다
스프링 클라우드 슬러시 Spring Cloud Sleuth: 제프킨 Zipkin과 함께 분산 추적 솔루션을 제공한다
스프링 클라우드 데이터 플로우 Spring Cloud Data Flow: 마이크로서비스 애플리케이션을 중심으로 오케이스트레이션을 구축하는 기능을 제공한다. DSL, GUI, REST API를 제공한다
스프링 클라우드 스트림 Spring Cloud Stream: 스프링 기반(및 스프링 부트 기반) 애플리케이션을 아파치 카프카나 RabbitMQ와 같은 메시지 브로커와 통합하기 위해 간단한 선언적 프레임워크를 제공한다
"우리는 시스템 아키텍처에 일관된 접근 방식이 필요하고 필수적인 측면이 이미 개별적으로 인식돼 있다고 생각한다. 반응성, 회복력, 탄력성, 메시지 기반 시스템을 원하며, 이러한 시스템을 리액티브 시스템이라고 한다. 리액티브 방식으로 구축된 시스템은 보다 유연하고 느슨하게 연결되며 확장 가능하므로 개발하거나 변경이 쉽다. 이들은 장애에 훨씬 더 관대해 장애가 발생하면 큰 장애를 일으키지 않고 간결하게 대처한다. 리액티브 시스템은 반응이 뛰어나 사용자에게 효과적인 대화식 피드백을 제공한다.
수 초 단위의 응답 시간 → 밀리초 단위의 응답 시간
여러 시간의 오프라인 유지 관리 → 100% 가용성
소량의 데이터 → 데이터 볼륨이 기하 급수적으로 증가
리액티브 시스템의 특성
반응성 Responsive; 시스템은 사용자에게 적시에 응답한다. 명확한 응답 시간 요구 사항이 설정되고 시스템은 모든 상황에서 이를 충족시킨다.
회복력 Resilient; 분산 시스템은 여러 구성요소를 사용해 구축된다. 이러한 구성요소 중 하나에서 오류가 발생할 수 있다. 리액티브 시스템은 지역화된 공간(예: 각 구성요소)에서 오류가 발생하도록 설계해야 한다. 이렇게 하면 로컬 장애가 발생해도 전체 시스템이 다운되는 것을 방지할 수 있다.
탄력성 Elastic; 리액티브 시스템은 다양한 부하에서 반응성을 유지한다. 과부하가 걸리면 로드가 다운될 때 시스템을 릴리스하는 동안 리소스를 추가할 수 있다. 탄력성은 범용 하드웨어와 소프트웨어를 사용해 달성된다.
메시지 주도 Message drive; 리액티브 시스템은 메시지(또는 이벤트)에 의해 구동된다. 이렇게 하면 구성요소들 사이의 낮은 결합이 보장돼 시스템의 다른 여러 구성 요소를 독립적으로 확장할 수 있다. 비차단 통신을 사용하면 스레드가 더 짧은 시간 동안 활성화된다.
이벤트에 반응 React to events; 리액티브 시스템은 메시지 전달을 기반으로 구축돼 이벤트에 빠르게 반응한다.
로드에 반등 React to load; 리액티브 시스템은 다양한 로드에서 반응성을 유지한다. 로드가 많을수록 더 많은 리소스를 사용하고 로드가 낮을 때는 해제한다.
장애 대응 React to failures; 리액티브 시스템은 장애를 정상적으로 처리할 수 있다. 리액티브 시스템의 구성요소는 장애를 지역화하기 위해 만들어졌다. 외부 구성은 구성요소의 가용성을 모니터링하고 필요할 때 구성요소를 복제할 수 있는 기능을 제공한다.
사용자에게 반응 React to users; 리액티브 시스템은 사용자에게 반응한다. 소비자가 특정 이벤트에 가입하지 않았다면 추가 처리를 수행하는 데 시간을 낭비하지 않는다
리액티브 유스케이스 - 주가 페이지
전통적인 접근 방식; 조사(poll)해서 주가가 변경됐는지 여부를 확인
리액티브 접근 방식; 이벤트 구독, 이벤트 발생, 가입 취소
전통적인 접근 방식과 리액티브 방식의 비교
자바에서 리액티브 프로그래밍 구현
리액티브 스트림 reactive streams
리액터 프레임워크 Reactor
스프링 웹 플럭스 프레임워크 Spring WebFlux framworks
스프링 모범 사례
메이븐 표준 디렉토리 레이아웃
src/main/java: 모든 애플리케이션 관련 소스코드
src/main/resources: 모든 애플리케이션 관련 리소스 스프링 컨텍스트 파일, 등록 정보 파일, 로깅 구성 등
src/main/webapp: 웹 애플리케이션과 관련된 모든 리소스, 뷰 파일(JSP, 뷰 템픗릿, 정적 콘텐츠 등)
src/test/java: 모든 단위 테스트 코드
src/test/resources: 단위 테스트와 관련된 모든 리소스
레이어 아키텍처를 사용한 애플리케이션 구축
프리젠테이션 레이어: 마이크로서비스에서 프리젠테이션 레이어는 REST 컨트롤러가 있는 위치다. 일반적인 웹 애플리케이션에서 프리젠테이션 레이어에는 뷰 관련 콘텐츠(JSP, 템플릿 및 정족 콘텐츠)가 포함된다. 프리젠테이션 레이어는 서비스 레이어와 통신한다.
서비스 레이어: 비즈니스 레이어의 껍데기 역할을 한다. 모바일, 웹 및 태블릿과 같은 다양한 뷰에는 다른 종류의 데이터가 필요할 수 있다. 서비스 레이어는 요구사항을 이해하고 프리젠테이션 레이어를 기반으로 올바른 데이터를 제공한다.
비즈니스 레이어: 모든 비즈니스 로직이 있는 곳이다. 또 다른 모범 사례는 대부분의 비즈니스 로직을 도메인 모델에 적용하는 것이다. 비즈니스 레이어는 데이터 레이어와 통신해 데이터를 가져오고 그 위에 비즈니스 로직을 추가한다.
퍼시스턴스 레이어: 데이터를 검색해 데이터베이스에 저장한다. 퍼시스턴스 레이어는 일반적으로 JPA 매핑 또는 JDBC 코드를 포함한다.
다른 레이어를 위한 별도의 컨텍스트 파일이 있다
application-context.xml
presentation-context.xml
services-context.xml
business-context.xml
persistence-context.xml
PresentationConfig.java
ServicesConfig.java
BusinessConfig
PersistenceConfig
중요한 레이어의 API와 impl 분리
예외 처리 모범 사례
예외 타입
체크된 예외: 서비스 메소드가 체크된 예외를 발생시키면 모든 소비자 메소드가 예외를 처리하거나 예외를 살생시켜야 한다.
언체크된 예외: 소비자 메소드는 서비스 메소드에 의해 발생한 예외를 처리하거나 발생시킬 필요가 없다.
예외 처리에 대한 스프링의 접근 방식
권장 접근법
스프링 구성 간결하게 유지
ComponentScan에서 basePackageClasses 속성 사용
스키마 참조에서 버전 번호를 사용하지 않는다
필수 의존 관계에 생성자 주입 선호
빈의 의존 관계 종류
필수 의존 관계: 빈에 사용하려는 의존 관계다. 의존 관계를 사용할 수 없을 때는 컨텍스트 로드되지 않는 편이 좋다.
선택적 의존 관계: 이들은 선택적 의존 관계로 항상 이용할 수 있지는 않다. 컨텍스트를 사용할 수 없는 경우에도 컨텍스트를 로드하는 것이 좋다.