1~3장. 스프링 부트 및 기초 지식
< 스프링 프레임워크 >
: 자바 기반의 application framework로 엔터프라이즈급 application을 개발하기 위한 다양한 기능을 제공함
(vs library?)
: 라이브러리는 내 코드가 라이브러리를 호출해서 사용하는 것.
프레임워크는 내 코드를 호출하는 것.
why? : application 개발에 필요한 기반을 제공해서 개발자가 비즈니스 로직 구현에만 집중하도록 하기 위해 존재
- 넓은 컨테이너(판때기, ApplicationContext) 위에 내가 만드는 클래스(ApplicationConfig.class)만 얹으면 개발 가능
- 스프링 bean(클래스를 활용하는 bean을 만듬)에 맞춰 만들면 서로서로 사용 쉬움
- 너무 자유롭지는 않아서 좋음
1. spring project 생성
1) spring application 부팅
- new SpringApplication()
- SpringApplication.run() : main()에서 이미 존재하는 SpringApplication 클래스의 run() 메서드를 호출하는 방식
(vs Java) : 이용할 class를 생성하고 static void main()에서 생성한 클래스를 선언하고 이용해서 실행
2) SpringBootApplication 어노테이션
(나중에..........)
2. 스프링 코어
- DI, IoC, container : 스프링의 근간을 이루고 전체 application을 통제하는데 활용
- resource, AOP, validation, SpEL : 많은 application에서 공통적으로 활용하기 좋은 기능
3. 스프링 Web MVC
: http 요청/응답 처리 (Web MVC는 계속 application이 요청이 올때까지 대기를 하고 있다가 요청이 오면 바로 처리하여 응답
- 필터, 인터셉터 : 웹에서 들어오는 요청을 필터링/공통적 처리 기술
- 예외처리 : 웹에서 들어온 처리를 하던 중 오류 발생시 안전하게 처리할 수 있도록
< DI, IoC, container >
1. IoC (inversion of control)
: 사용자가 직접 클래스를 생성하지 않고 프레임워크(spring)가 제어하도록 하는 것
2. DI (dependency injection 의존성 주입)
: 사용할 객체를 직접 만들지 않고 외부 컨테이너가 생성한 객체를 주입받아 사용하는 방식
- A가 B를 사용한다.
ex) '결제서비스(A)가 머니어댑터(B)와 편의점 할인(B)을 사용한다.'는 것을 application context(spring)이 서비스(A)가 어떤 객체(B)를 사용할지를 정해줌.
- 방법: Bean : 사용할 클래스로 객체를 생성하여 반환하는 것
① XML을 통한 Bean(사용할 클래스로 객체를 생성하여 반환하는 것) 등록 → 번거로움
② XML ComponentScan을 통한 Bean 등록
(어노테이션 : @Controller, @RestController, @Service, @Component, @Repository 등)
③ JavaConfig을 통한 Bean 등록 → 편의점 결제 서비스
(@Configuration)
④ JavaConfig ComponeneScan을 통한 Bean 등록 : ② + ③
(@Configuration, @ComponentScan(어디부터 싹 다), @Component... 이용)
⑤ @SpringBootApplication으로 프로젝트 생성하면 바로 생김
+ 추가 설명
1. Bean의 구현체가 여러개이면?
이게 무슨 말인가?!?!
할인적용 방법이 두가지가 있다. 편의점에 따른 할인이냐, 지불방법에 따른 할인이냐.
이 두가지 할인정책의 각 클래스는 둘 다 bean으로 등록되어 있다. 그래서 한 가지 결정을 해야하는 상황
이때 사용하는 것이 @Primary.
우선적용을 뜻하는 것으로 편의점할인 클래스에 붙여주면 인터페이스에서 자동으로 먼저 편의점으로 할인을 적용시키도록 하고, 반대이면 반대로 적용된다.
BUT! 구현체가 2개보다 훨씬 많은 것이라면...? @Qualifier(BeanName).
인터페이스를 사용하는 구간(편의점 서비스)에 @Qualifer(bean이름)을 전줄에 붙인다.
2. Bean의 생성 정의 @Scope("방법")
1) 싱글톤 : 재활용
2) prototype : 매번 새로 만듬
- request에 따라, session에 따라
3. spring 환경설정 : @Profile("환경이름")
- 실무에서는 환경을 다양하게 하기 때문에 해당 환경에서만 동작하는 Bean을 만드는 것이 중요
- 환경이름?
- (!, &, |) 로 사용가능.
@Profile("!환경변수이름") : 환경변수가 아닐때 적용
1) class 단위
@Configuration / @Component
@Profile("환경이름")
2) 메서드 단위
@Bean
@Profile("환경이름")
3) 여러개
: -Dspring.profiles.active = 환경이름들 콤마로 나열
< resource, AOP, validation, SpEL >
1. resource : 외부자원(http, 이미지, 파일 등) 가져오기
- resource 인터페이스 (spring에서 제공)
public interface Resource extends InputStreamSource {
boolean exists();
boolean isReadable();
boolean isOpen();
boolean isFile();
URL getURL() throws IOException;
URI getURI() throws IOException;
File getFile() throws IOException;
ReadableByteChannel readableChannel() throws IOException;
long contentLength() throws IOException;
long lastModified() throws IOException;
Resource createRelative(String relativePath) throws IOException;
String getFilename();
String getDescription();
}
- resource 목록들
: UrlResource, ClassPathResource, FileSystemResource, SevletContextResource, InputStreamResource 등 존재
- ResourceLoader 인터페이스 : 프로젝트 내의 resource를 로딩할 때 사용
public interface ResourceLoader {
Resource getResource(String location);
ClassLoader getClassLoader();
}
- ResourcePatternResolver
등등등등등...
자세한 내용은 프로젝트 하면서 더 알아보고 추가해보기 :)
2. AOP (관점지향 프로그래밍) : 여러 메서드에서 동일한 코드가 반복될 때 사용
- 로깅 : 요청의 내용은? 어떤 요청이 들어왔는데 실제로 나가는 응답은 무엇인가? or 요청이 들어온 시간과 응답한 시간? 등의 정보를 기록하는 행위
- 트랜잭션 : DB의 상태를 변화시키는 작업 단위로 일련의 작업이 동시에 모두 다 성공 및 실패. (송금 : 돈을 보내면 상대방이 돈을 받는 것. 중간에 에러가 나면 돈을 보낸 것과 받는 것 둘 다 실패로 적용시키는 것)
- 인증, 캐쉬
이것들이 반복된다고?
상품 정보를 등록하는 것과 상품 정보를 조회하는 두 가지 작업이 있다.
어쨌든 이 두 작업 모두 DB를 접근해야하는 상황이 발생. 즉, 같은 트랜잭션 영역에서 수행한다.
또한 로깅 마찬가지로 기록하는 행위는 같다.
자세한 내용은 또 공부하면서 추가하기 :)
3. Validation, data binding : data를 믿고 쓰기, 데이터를 원하는 형식으로 받고 싶을 때
1) validation
: 다른 서버에서 요청이 날라올 때 그 내용이 잘못된 내용인지 확인하는 것
- 종류?
: 데이터 검증 - 필수data 존재?, 문자열길이/숫자범위 괜찮은지, 데이터의 형식에 맞춘 데이터인지?
: 비즈니스 검증 - 서비스 정책에 따른 데이터 확인 (배달앱에서 배달 요청할 때 주문건이 결제완료상태인가?)
- Spring에서 validation 방법?
① Java Bean을 통한 검증
public class MemberCreationRequest {
@NotBlank(message="이름을 입력해주세요.")
@Size(max=64, message="이름의 최대 길이는 64자 입니다.")
private String name;
@Min(0, "나이는 0보다 커야 합니다.")
private int age;
@Email("이메일 형식이 잘못됐습니다.")
private int email;
}
ㄴ dto에 어노테이션으로 명시
@PostMapping(value = "/member")
public MemeberCreationResponse createMember(
@Valid @RequestBody final MemeberCreationRequest memeberCreationRequest) {
// 검증 성공 후 실행될 것들
}
ㄴ 웹에서 요청을 받는 말단에서
② Spring validator 인터페이스 구현을 통한 검증
public class Person {
private String name;
private int age;
}
ㄴ 클래스 생성
public class PersonValidator implements Validator {
/**
* 이 validator은 Person 객체에 대해서만 검증 가능
*/
public boolean supports(Class clazz) {
return Person.class.equals(clazz);
}
public void validate(Object obj, Errors e) {
ValidationUtils.rejectIfEmpty(e, "name", "name.empty");
Person p = (Person) obj;
if (p.getAge() < 0) {
e.rejectValue("age", "negativevalue");
} else if (p.getAge() > 110) {
e.rejectValue("age", "too.darn.old");
}
} }
ㄴ Person 객체에 대한 validator
2) data binding
: validation 후, 그 data를 특정 도메인 객체에 저장해서 우리 프로그램에 Request에 담아주는 것
- 방법?
① Converter<Source,Target> Interface
: S라는 타입을 받아서 T라는 타입으로 변환해주는 인터페이스
package org.springframework.core.convert.converter;
public interface Converter<S, T> {
T convert(S source);
}
ㄴ 인터페이스 모양
// 요청
GET /user-info
x-auth-user : {"id":123, "name":"Paul"}
// 유저 객체
public class XAuthUser {
private int id;
private String name;
}
@GetMapping("/user-info")
public UserInfoResponse getUserInfo(
@RequestHeader("x-auth-user") XAuthUser xAuthUser){
// get User Info logic here...
}
@Component
public class XAuthUserConverter implements Converter<String, XAuthUser> {
@Override
public XAuthUser convert(String source) {
return objectMapper.readValue(source, XAuthUser.class);
}
}
ㄴ json을 특정 dto에 담는 내용 (string을 XAuthUser로)
② Formatter
: 특정객체 ↔ String 변환
package org.springframework.format.datetime;
@Component
public final class DateFormatter implements Formatter<Date> {
public String print(Date date, Locale locale) {
return getDateFormat(locale).format(date);
}
public Date parse(String formatted, Locale locale) throws ParseException {
return getDateFormat(locale).parse(formatted);
}
}
ㄴ Date ↔ String
4. SpEL : Spring의 모든 영역에서 사용 가능한 표현언어
< Spring MVC > : 웹 개발 기술
- model : 이동하는 데이터들
- view : 화면
- controller : 모델/뷰를 응답
자세한 건 뒤에서...
< 기초 지식 >
- 서버 간 통신 : 클라이언트 ↔ 서버 (HTTP/HTTPS)
1. spring boot 동작
- 서블릿 : client의 요청 처리 및 응답하는 자바 웹 프로그래밍
- 서블릿 컨테이너 : 서블릿 객체 생성 및 관리
(1) : DS(dispatcher servlet)에 요청이 들어오면 DS는 핸들러(=controller) 매핑을 통해 요청 URI에 매핑된 핸들러를 탐색
(2) : 핸들러 어댑터로 컨트롤러를 호출
(3) : 핸들러 어댑터에 컨트롤러의 응답이 들어오면 ModelAndView로 응답을 가공해 반환
(4) : 뷰 형식으로 리턴하는 controller를 사용할 때는 뷰 리졸버를 통해 뷰를 받아 리턴
2. 레이어드 구조 (Spring MVC)
: application의 component를 유사한 기준으로 레이어로 묶어 수평적으로 구성한 구조
- 프레젠테이션 : 클라이언트의 요청을 해석/응답 (View, Controller)
- 비즈니스 : application이 제공하는 기능을 정의 (Model)
- 데이터 접근 : DB에 접근 (Model)
1) 프레젠테이션
- UI
- client로부터 data/request 받고 response 전달
2) 비즈니스
- Service
- transaction 처리, validation
3) 데이터 접근
- Persistence
- DB 접근
3. 디자인 패턴
: 소웨를 설계할 때 발생하는 문제에 대한 해결책
1) 종류
- GoF : 생성, 구조, 행위 (자세한 내용은 인터넷 참고)
4. REST API : 애플리케이션 인터페이스(client가 서버에 접근하고 자원 조작 가능)
- REST? : WWW과 같이 주고받는 resource에 이름을 규정하고, URI에 명시해 HTTP(get, post, put, delete)를 통해 해당 자원 상태를 주고받는 것.
1) 특징
- 유니폼 인터페이스 : HTTP 규약 따름. 많은 곳에서 호환 가능
- 무상태성 : 서버에 상태 정보를 따로 보관X -> request를 개별적으로 처리
- 캐시 가능성 : 같은 요청에 대해서 이전의 데이터 가져옴 (=서버 transaction 부하↓)
- 레이어 시스템
- 클라이언트/서버 구조 : 의존성↓
2) URI 설계 규칙
- URI 마지막 '/' 안붙임 ex) http://localhost:8080
- 언더바X.
- URL에는 동사X 명사O
- URL는 소문자로 작성