# 11월 1일 - 스프링AOP와 AspectJ 차이점
# Spring AOP
IoC/DI/프록시 패턴/자동 프록시 생성 기법/빈 오브젝트의 후처리 조작기법 등을 통해 AOP를 지원하며, 이와 같은 AOP는 스프링과 기본 JDK를 통해 구현 가능하다. 즉 간접적인 방식을 통해 AOP를 지원한다. 해당 Spring AOP는 프록시 방식의 AOP이다. 즉 프록시 디자인 패턴을 사용한다.
스프링 AOP의 프록시 빈 생성 절차는 다음과 같다.
- 빈 설정파일을 통한 빈 오브젝트 생성
- (생성된 빈을 이용하여) 빈 후처리기를 통해 컨테이너 초기화 시점에서 자동으로 프록시 생성(DefaultAdvisorAutoProxyCreator.class/BeanPostProcessor.class),
- 포인트컷을 활용하여, 프록시를 적용할 대상을 지정한다.
- 프록시 빈 오브젝트 생성 및 IoC 컨테이너에 등록
# AspectJ
바이트코드 생성과 조작을 통해 AOP를 실현한다. Target 오브젝트를 뜯어 고쳐서 부가기능을 직접 넣어주는 직접적인 방식이다.
# AOP용어
- Target: 부가기능을 부여할 대상을 뜻한다. 즉, 주기능을 얘기한다.
- Aspect: AOP의 기본 모듈이다. 한개 또는 그 이상의 포인트컷과 어드바이스의 조합으로 만들어진다.
- Advice: 실질적으로 부가 기능의 구현체이다. Advice의 유형은 다음과 같다. Before, After, Around, AfterReturning, AfterThrowing이 있다.
- Before: Target을 실행하기전에 부가 기능 실행
- After: Target실행 후 (해당 Target Exception 또는 정상리턴 여부 상관없이) 실행
- Around: Before + AfterReturning
- AfterReturning: Target 실행 후 성공적인 리턴할 때
- AfterThrowing: Target 실행하다, Exception 던질 때
- Join-Point: Advice가 적용될 위치를 표시한다(ex:메소드 실행 단계).
- Point-Cut: Advice를 적용할 Target를 선별하는 역할을 한다. Annotation 또는 메소드의 정규식을 통해 표현한다.
- Cross-Cutting Concertn: 횡단 공통 관심사이다. 이것은 이미지를 통해 연상하는 것이 더 빠르다.
# AOP Weaving
Aspect(부가기능)와 Application(핵심기능)의 Linking을 하는 과정이다. 해당 객체들을 묶어 새로운 객체를 생성한다.
- Spring AOP
이미, 위에서 Weaving 절차를 설명하였다. Spring AOP의 Weaving 절차는 RunTime이다(프록시 빈 생성하는 것, IoC 컨테이너 초기화 작업할 때, 그러니까 WAS 가동할 때). 인터페이스 기준으로 하는 JDK Dynamic Proxy와 Class 기준으로 하는 CGLib Proxy가 존재한다. CGLib Proxy의 경우, AspectJ의 Weaving 처럼 바이트 코드를 조작한다. SpringAOP는 JDK Dynamic Proxy 패턴을 선호한다. 또한 Proxy 패턴 자체가 인터페이스를 끼고하는 페턴이다.
- AspectJ
실제, AJC(Apsect Compiler)를 이용하여 Woven System 생성한다. 즉 부가기능과 핵심기능이 합쳐진 클래스 파일을 생성한다. AspectJ의 Weaving 타입은 아래와 같다. Compile-Time Weaving: Aspect의 클래스와 Aspect를 사용하는 class들을 AJC를 통해 컴파일을 한다. JAR를 이용하여 Weaving을 하는 경우, Post-Compile Weaving(Binary Weaving)을 사용하며, 일반 소스 코드의 경우, 일반 Compile-Time Weaving을 사용한다. Load-Time Weaving: 클래스로더를 통해 클래스가 JVM에 로딩되는 시점에 클래스의 바이트 코드를 조작한다. 즉, 객체를 메모리에 적재할 때 Weaving을 실현한다. 때문에, 다른 Weaving보다 속도 측면에서는 느리다.
# Spring AOP vs AspectJ
일단 AspectJ가 8~35배 빠르다. SpringAOP는 Aspect당 기타 AOP 관련 메소드를 추가적으로 호출하기 때문에 바이트코드를 직접적으로 건드린 AspectJ에 비하면 느릴 수 밖에 없다.
- Spring AOP는 퓨어 자바를 통해 구현 가능
- AsepctJ는 Load-Time Weaving을 하지 않는한, AJC를 통한 컴파일 절차가 필요하다.
- Spring AOP는 method level weaving만 가능(근데 보편적으로 method level weaving만 사용....)
- Spring AOP는 Spring 프레임워크에서 한정적이지만 AspectJ는 모든 JVM에서 가능하다.
- Spring AOP는 execution 포인트컷만(위에서 설명한 메소드 정규식) 사용가능
- AspectJ가 빠름
- Spring AOP 복잡도 승리(프록시 패턴을 활용하여 복잡도가 AspectJ보다 훨씬 낮다.)
# 11월 3일 - SSE
# 실시간 웹 애플리케이션 개발시 고려 기술
- polling(client pull)
- websocket(server push)
- SSE(server push)
# polling
- 클라이언트가 일정한 주기로 서버에 업데이트 요청을 보내는 방법.
- 지속적인 HTTP 요청이 발생하기 때문에 리소스 낭비가 발생한다.
# websocket
- 실시간 양방향 통신을 위한 스펙으로 서버와 브라우저가 지속적으로 연결된 TCP라인을 통해 실시간으로 데이터를 주고받을 수 있도록 하는 HTML5 사양이다.
- 연결지향 양방향 전이중 통신이 가능하며 채팅, 게임, 주식 차트 등에 사용된다.
- polling은 주기적으로 HTTP 요청을 수행하지만, websocket은 연결을 유지하여 서버와 클라이언트 간 양방향 통신이 가능하다
# SSE
- 이벤트가 서버 -> 클라이언트 방향으로만 흐르는 단방향 통신 채널이다.
- SSE는 클라이언트가 polling과 같이 주기적으로 http 요청을 보낼 필요없이 http 연결을 통해 서버에서 클라이언트로 데이터를 보낼 수 있다.
# 11월 9일 - static, final, static final의 차이
# static
- static은 고정된 이라는 뜻이다. 메모리를 공유하여 사용하기 때문에 필요할때 바로바로 호출하거나 데이터를 가져올 수 있게 된다.
- 즉,
객체 생성없이 사용할 수 있는 필드와 메소드를 생성
하고자 할 때 활용한다. - 공용데이터에 해당하거나 인스턴스 필드를 포함하지 않는 메소드를 선언하고자 할 때 이용한다.
class StaticExample {
// static 필드 선언
static int circle_dot = 3;
static int square_dot = 4;
// static 메서드 선언
static int multi(int a, int b){
return a * b;
}
}
// static 멤버 사용 클래스
public class UsedStaticExample {
public static void main(String[] args) {
int a = StaticExample.circle_dot;
int b = StaticExample.square_dot;
int result = StaticExample.multi(a, b);
System.out.println("꼭지점 곱셈 = " + result);
}
}
# final
- final은 최종적인 이라는 의미이다.
- 즉, 해당 변수는 값이 저장되면 최종적인 값이 되므로,
수정이 불가능
하다는 의미이다. - 주로 상수로 변수를 사용하기 위해 사용하거나 오버라이딩을 막기 위해 사용한다. 만약 클래스에 final을 사용하면 상속을 막아준다.
- 따라서 변수, 함수, 클래스의 명시적 제한을 나타내기 위해 사용하며, 이를 통해 다양한 팀 협업시 코드의 가독성을 높여주는 효과를 얻을 수 있다.
// final 필드 선언 초기화
class Info {
final String host = "localhost:8080";
final String url;
public Info(String url) {
this.url = url;
}
}
public class UsedFinalExample {
public static void main(String[] args) {
Info testUrl = new Info("/mainType=A&subType=B");
System.out.println(testUrl.host);
System.out.println(testUrl.url);
String finalUrl = testUrl.host + testUrl.url;
System.out.println(finalUrl);
}
}
# static final(상수)
- 두개를 합쳐서 생각해보면 고정되어 최종적으로 사용된다고 보면된다.
- 즉, 클래스 자체에 존재하는 단 하나의 상수이다.(클래스자체로 존재하여 접근가능하고 불변하다)
- 따라서 클래스의 선언과 동시에 반드시 초기화가 필요한 클래스 상수이다.
public class UsedStaticFinal {
// 상수 선언
static final double INCH = 2.54;
static final double CM = 1;
static final double MONITOR_WIDTH;
// 상수 초기값 선언
static {
MONITOR_WIDTH = 14 * INCH * CM;
}
// 상수 사용
public static void main(String[] args) {
System.out.println("14인치 모니터 cm는? "+ MONITOR_WIDTH);
}
}
# 11월 16일 - save메서드로 살펴보는 persist와 merge 개념
# SimpleJpaRepository
의 save() 메서드
@Transactional
public <S extends T> S save(S entity) {
if (this.entityInformation.isNew(entity)) {
this.em.persist(entity);
return entity;
} else {
return this.em.merge(entity);
}
}
# persist메소드와 merge메소드의 차이점
- persist메소드 : 새 Entity를 영속화
- merge메소드 : 준영속 상태의 Entity를 다시 영속화
# 11월 23일 - @valid와 @validated
https://mangkyu.tistory.com/174
# @Valid의 개념 및 사용법
- @Valid는 JSR-303
표준 스펙(자바 진영 스펙)
으로써 빈 검증기(Bean Validator)를 이용해 객체의 제약 조건을 검증하도록 지시하는 어노테이션이다. - 다음과 같은 의존성을 추가 해주면 자동 설정 됨
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-validation'
- 호출 하는 클래스 필드에 다음과 같이 어노테이션을 단다.
@Getter
@RequiredArgsConstructor
public class AddUserRequest {
@Email
private final String email;
@NotBlank
private final String pw;
@NotNull
private final UserRole userRole;
@Min(12)
private final int age;
}
- 그리고 다음과 같이 컨트롤러의 메소드에 @Valid를 붙여주면 유효성 검증이 진행된다.
@PostMapping("/user/add")
public ResponseEntity<Void> addUser(@RequestBody @Valid AddUserRequest addUserRequest) {
...
}
# @Valid의 동작 원리
- 컨트롤러 메소드의 객체를 만들어주는 ArgumentResolver 의해 처리되기 때문에 컨트롤러에서만 동작
- 검증에 오류가 있다면 MethodArgumentNotValidException 예외가 발생하게 되고, 디스패처 서블릿에 기본으로 등록된 예외 리졸버(Exception Resolver)인 DefaultHandlerExceptionResolver에 의해 400 BadRequest 에러가 발생
# @Validated의 개념 및 사용법
@Validated는 JSR 표준 기술이 아니며 Spring 프레임워크에서 제공하는 어노테이션 및 기능
AOP 기반으로 메소드의 요청을 가로채서 유효성 검증을 진행해주는 @Validated를 제공
다음과 같이 클래스에 @Validated를 붙여주고, 유효성을 검증할 메소드의 파라미터에 @Valid를 붙여주면 유효성 검증이 진행된다.
@Service
@Validated
public class UserService {
public void addUser(@Valid AddUserRequest addUserRequest) {
...
}
}
# @Validated의 동작 원리
- @Validated는 AOP 기반으로 메소드 요청을 인터셉터하여 처리된다. @Validated를 클래스 레벨에 선언하면 해당 클래스에 유효성 검증을 위한 인터셉터(MethodValidationInterceptor)가 등록된다. 그리고 해당 클래스의 메소드들이 호출될 때 AOP의 포인트 컷으로써 요청을 가로채서 유효성 검증을 진행한다.
- @Validated를 사용하면 컨트롤러, 서비스, 레포지토리 등 계층에 무관하게 스프링 빈이라면 유효성 검증을 진행할 수 있다.
- @Valid에 의한 예외는 MethodArgumentNotValidException이며, @Validated에 의한 예외는 ConstraintViolationException이다.
# 다양한 제약조건 어노테이션
- @NotNull: 해당 값이 null이 아닌지 검증함
- @NotEmpty: 해당 값이 null이 아니고, 빈 스트링("") 아닌지 검증함(" "은 허용됨)
- @NotBlank: 해당 값이 null이 아니고, 공백(""과 " " 모두 포함)이 아닌지 검증함
- @AssertTrue: 해당 값이 true인지 검증함
- @Size: 해당 값이 주어진 값 사이에 해당하는지 검증함(String, Collection, Map, Array에도 적용 가능)
- @Min: 해당 값이 주어진 값보다 작지 않은지 검증함
- @Max: 해당 값이 주어진 값보다 크지 않은지 검증함
- @Pattern: 해당 값이 주어진 패턴과 일치하는지 검증함
# @Valid와 @Validated 유효성 검증 차이
위에서 살펴보았듯 @Validated의 기능으로 유효성 검증 그룹의 지정도 있지만 거의 사용되지 않으므로 유효성 검증 진행을 기준으로 차이를 살펴보도록 하자.
- @Valid
- JSR-303 자바 표준 스펙
- 특정 ArgumentResolver를 통해 진행되어 컨트롤러 메소드의 유효성 검증만 가능하다.
- 유효성 검증에 실패할 경우 MethodArgumentNotValidException이 발생한다.
- @Validated
- 자바 표준 스펙이 아닌 스프링 프레임워크가 제공하는 기능
- AOP를 기반으로 스프링 빈의 유효성 검증을 위해 사용되며 클래스에는 @Validated를, 메소드에는 @Valid를 붙여주어야 한다.
- 유효성 검증에 실패할 경우 ConstraintViolationException이 발생한다.
← 2022년 10월 2022년 8월 회고 →