Skip to content

태그: 서버

ProxyFactoryBean
aop
스프링은 서비스 추상화를 프록시 기술에도 동일하게 적용한다. 따라서 스프림은 일관된 방법으로 프록시를 만들 수 있게 도와주는 추상 레이어를 제공한다. ProxyFactoryBean은 프록시를 생성해서 빈 오브젝트로 등록하게 해주는 팩토리 빈이다. ProxyFactoryBean은 순수하게 프록시를 생성하는 작업만을 담당하고 프록시를 통해 제공해줄 부가기능은 별도의 빈에 둘 수 있다. ProxyFactoryBean이 생성하는 프록시에서 사용할 부가기능은 MethodInterceptor 인터페이스를 구현해서 만든다. MethodInterceptor는 InvocationHanler와 비슷하지만 한가지 다른점이 있다. InvocationHandler의 invoke() 메소드는 오브젝트에 대한 정보를 제공하지 않는다.
Spring AOP
aop
AOP란 Aspect Oriented Programming의 약자로 관점 지향 프로그래밍이라고 한다. 여기서 Aspect(관점)이란 흩어진 관심사들을 하나로 모듈화 한 것을 의미한다. 객체 지항 프로그래밍(OOP)에서는 주요 관심사에 따라 클래스를 분할한다. 이 클래스들은 보통 SRP(Single Responsibility Principle)에 따라 하나의 책임만을 갖게 설계된다. 하지만 클래스를 설계하다보면 로깅, 보안, 트랜잭션 등 여러 클래스에서 공통적으로 사용하는 부가 기능들이 생긴다. 이들은 주요 비즈니스 로직은 아니지만, 반복적으로 여러 곳에서 쓰이는 데 이를 흩어진 관심사(Cross Cutting Concerns)라고 한다. AOP 없이 흩어진 관심사를 처리하면 다음과 같은 문제가 발생한다.
Spring에서 aspectj weaving사용하기
aop
Spring은 객체지향적으로 AOP 기술을 구현하기 위해 프록시 패턴의 관점을 선택했다. 이러한 패턴의 추상적인 관점을 구체화하기 위해, Java에서 기본적으로 제공해주고 있는 JDK Dynamic Proxy(프록시 패턴의 관점의 구현체)를 기반으로 추상적인 AOP 기술을 객체 모듈화하여 설계하였다. 또한 Spring은 성숙한 AOP 기술을 제공해주기 위해 Spring 2.0 부터 @AspectJ애노테이션 방식을 지원하였고, Aspect를 구현하는데 있어 AspectJ5 라이브러리에 포함된 일부 애노테이션을 사용할 수 있다. AspectJ의 강력한 AOP 기술을 Spring에서 쉽게 구현할 수 있기 때문에 개발자는 비즈니스 개발에 보다 집중할 수 있다. 물론, @AspectJ 애노테이션 방식을 통해 구현된
트랜잭션 전파
트랜잭션
트랜잭션 전파란 트랜잭션 경계에서 이미 진행 중인 트랜잭션이 있을 때 또는 없을 때 어떻게 동작할 것인가를 결정하는 방식을 말한다. 1. PROPAGATION_REQUIRED 가장 많이 사용되는 트랜잭션 속성이다. 진행 중인 트랜잭션이 없으면 새로 시작하고, 이미 시작된 트랜잭션이 있으면 이에 참여한다. DefaultTransactionDefinition의 트랜잭션 전파 속성은 바로 이 PROPAGATION_REQUIRED이다. 2. PROPAGATION_REQUIRED_NEW 항상 새로운 트랜잭션을 시작한다. 즉. 앞에서 시작된 트랜잭션이 있든 없든 상관없이 새로운 트랜잭션을 만들어서 독자적으로 동작하게 한다. 3. PROPAGATION_NOT_SUPPORTED 트랜잭션이 없이 동작하도록 만들
AOT
spring
Spring AOT 엔진은 빌드 시 스프링 애플리케이션을 분석하고 최적화하는 도구이다. 또한 AOT 엔진은 GraalVM Native Configuration이 필요로 하는 reflection configuration을 생성해준다. 이것은 Spring native 실행 파일로 컴파일 하는데 사용되고 이후에 애플리케이션의 시작 시간과 메모리 사용량을 줄일 수 있게 한다. 그러한 변환은 Maven과 Gradle 스프링 AOT 플러그인에 의해 수행된다. AOT 엔진은 최적화된 애플리케이션 컨텍스트와 애플리케이션을 위해 특별히 제작된 스프링 팩토리(Spring Boot 뒤의 플러그인 시스템)를 생성하기 위해 빌드 시 조건을 평가한다. 이를 통해 아래와 같은 효과를 볼 수 있다. 런타임시 필요한 스프링 인프라가
@TransactionalEventListener
event
Event를 사용할 때 기본적으로 사용하는 @EventListener는 event를 publishing 하는 코드 시점에 바로 publishing*한다. 하지만 우리가 퍼블리싱하는 event는 대부분 메인 작업이 아닌 서브의 작업이 많고 비동기로 진행해도 되는 경우도 많다. 다른 도메인 로직인 경우도 있다. 이럴 경우 조금 애매해지기도 한다. 아래 예를 보자. 아래코드는 @Transactional로 메서드가 하나의 트랜잭션으로 묶여있다. 이 메서드를 실행했을때, 1번과 2번이 정상적으로 마무리되고 3번이 발생하는 도중에 예외처리가 발생하면 어떻게 될까? 3번이 실패했으면 같은 트랜잭션으로 묶여있는 1번도 함께 롤백될 것이다. 하지만 2번은 발행된 이벤트를 listen하는 별도의 구현체가 이후의 동작을 수
Cascade
jpa
cascade 옵션은 jpa를 사용할때 @OneToMany나 @ManyToOne에 옵션으로 줄 수 있는 값이다. cacade 옵션을 사용하면 부모 엔티티에 상태 변화가 생길 때 그 엔티티와 연관되어있는 엔티티에도 상태 변화를 전이시킬 수 있다. 즉, 자식 엔티티의 생명주기를 관리할 수 있다. cascade 타입의 종류 PERSIST 부모 엔티티를 저장하면 자식 엔티티까지 함께 저장한다. 다시말해, 명시적으로 부모엔티티와 연관관계를 가진 자식 엔티티 영속화시킬때 따로 명시할 필요 없이 부모.자식 = 자식 인스턴스 과 같이 적으면 자식 엔티티도 데이터베이스에 자동으로 저장된다. MERGE 데이터베이스에서 가져온 부모 객체를 통해 자식 엔티티의 정보를 수정하여 병합했을때 변경 결과가 자식 엔티티에 반
GenerateValue Column에 값을 넣는다면
jpa
Hexagonal architecture를 사용해서 구현하다 문제가 생겼다. 해당 프로젝트에선 기본 PK로 UUID를 사용했고, 새로 생성한 도메인 모델은 id 값을 UUID(0, 0)으로 설정해서 사용했다. (여기서 중요하진 않지만 생성 전략은 IdentifierGenerator로 TimeBasedUUID를 생성할 수 있도록 직접 정의된 상태였다.) UUID(0, 0)으로 설정해주다 보니 기존에는 새 insert문을 날려야하는 경우 isNew가 Persistable 기본 전략에 따라 false로 들어갔고, merge가 호출되었다. 여기에서 알아봤던 것 처럼 영속성 컨텍스트에 등록되지 않은 객체에 대해 merge를 호출하면, 어떤 update문(혹은 insert문)을 날려야하는지를 알아야 하기 때문에 sel
Hibernate dialect
jpa
하이버네이트가 데이터베이스와 통신을 하기 위해 사용하는 언어를 Dialect라고 한다. 모든 데이터베이스에는 각자의 고유한 SQL언어가 있는데, 관계형 데이터베이스끼리 형태나 문법이 어느정도 비슷하긴 하지만, 완전히 똑같지는 않다. 예를 들어 Oracle 쿼리 구문과 MySQL 쿼리구문은 다르다. 하지만, 하이버네이트는 한 데이터베이스관리시스템(DBMS)에 국한되지않고, 다양한 DBMS에 사용 가능하다. 즉 내부적으로 각자 다른 방법으로 처리하고 있는 것이다. 그렇기 때문에특정 벤더(DBMS)에 종속적이지 않고, 얼마든지 대체가능하다. JPA에서는 아래와 같이 Dialect라는 추상화된 언어 클래스를 제공하고 각 벤더에 맞는 구현체를 제공하고 있다. spring: datasource:
JDBC Object Mapping Fundamentalsentity
jpa
스프링 데이터가 객체를 매핑할 떄 담당하는 핵심 역할은 도메인 객체 인스턴스를 생성하고, 여기에 저장소 네이티브 데이터 구조를 매핑하는 일이다. 여기에는 두 가지의 핵심적인 단계가 있다. 노출된 생성자중 하나로 인스턴스 생성하기. 나머지 프로퍼티 채우기. 엔티티(Entity) 생성 Spring Data JDBC에서 엔티티 객체를 생성하는 알고리즘은 3가지이다. 기본 생성자가 있는 경우 기본생성자를 사용한다. 다른 생성자가 존재해도 무시하고 우선적으로 기본생성자를 사용한다. 매개변수가 존재하는 생성자가 하나만 존재한다면 해당 생성자를 사용한다. 매개변수가 존재하는 생성자가 여러개 있으면 @PersistenceConstructor 어노테이션이 적용된 생성자를 사용한다. 만약 @PersistenceCons
FetchJoin
jpql
fetch join은 JPQL에서 성능 최적화를 위해 제공하는 기능이다. 페치 조인은 연관된 엔티티나 컬렉션을 한 번에 같이 조회해준다. 일반적으로 연관관계가 맺어진 엔티티를 조회할때, N+1문제를 해결하기 위해서 FetchType.LAZY를 사용하는 경우가 있다. 하지만 두 엔티티를 모두 조회해야하는 경우엔 두개의 쿼리를 날려야하기 때문에 N+1문제가 동일하게 발생한다. 이럴 때 fetch join을 사용하면 하나의 쿼리로 두 엔티티를 한 번에 조회할 수 있다. 1:N 조인에서 fetch join을 사용하면 결과의 갯수가 늘어날 수 있다.(‘1’쪽에서 조회해야하는 엔티티의 총 갯수가 아닌, ‘1’쪽의 엔티티 갯수만큼의 결과가 조회된다.) 이 경우 JPQL의 DISTINCT를 사용해서 결과의 갯수를 줄일
경로표현식
jpql
자바에서 인스턴스화된 객체로 클래스의 변수나 메서드에 접근할 때 .을 이용해 접근하는 것 처럼, jpql 쿼리에서 .으로 객체의 값에 점을 찍어 객체 그래프를 탐색하는 것을 경로 표현식이라고 한다. 경로 유형별 동작 상태 필드(State Field) 상태 필드는 일반적인 값을 저장하기 위한 필드이다. 즉, int, varchar등의 자료형을 가지는 기본적인 데이터를 저장한다. 상태필드는 더 나아갈 경로가 존재하지 않으므로 jpql에서 부가적인 조인 등의 탐색 또한 일어나지 않는다. 연관 필드(Association field) 연관 필드는 연관관계가 맺어진 외래 테이블의 값을 위한 필드이다. 단일 값 연관 필드와 컬렉션 값 연관 필드로 나뉜다. 단일 값 연관 필드 @ManyToOne, @OneToOne
OrphanRemoval
jpa
cascade 옵션을 사용하면 부모 엔티티에 상태 변화가 생길 때 그 엔티티와 연관되어있는 엔티티에도 상태 변화를 전이시킬 수 있다. 그러나 cascade 옵션을 사용한다고 해서 부모 엔티티에서 자식 엔티티의 생명주기를 완전히 통제할 수 있는 것은 아니다. cascade의 REMOVE 옵션은, 부모 엔티티를 삭제했을때 그 엔티티를 참조하고 있는 자식 엔티티(해당 부모 엔티티를 Foreign Key로 가지고있는 엔티티)도 함께 삭제해준다. 하지만 부모 엔티티에서 자식 엔티티를 삭제했을때에는 그 참조를 끊어줄 뿐, 그 자식 엔티티를 같이 삭제해주진 않는다. (심지어 FK에 NotNull 제약조건을 걸어놨으면 아무 변화도 생기지 않는다) 그럴 때 사용할 수 있는 것이 OrphanRemoval이다
Paging
querydsljpa
Querydsl에서 페이징하는 방법을 알아보자. Page는 인터페이스이기 떄문에, Page를 반환하기 위해선 Page를 구현한 구체클래스를 생성해야한다. 그렇기 때문에 아래 코드에선 스프링 데이터에 있는 PageImpl 클래스를 사용하여 return 하도록 한다. fetchResults()를 사용하여 total count쿼리와 결과 리스트를 한 코드로 조회하도록 할 수도 있지만, fetchResults()와 fetchCount()가 특정 상황에서 제대로 동작하지 않는 이슈때문에 depercated 되었으므로 따로 count를 조회하여 반환하는 방식을 택했다. 원하는 컬럼을 Dto로 만들어서 조건에 따라 조회한 후 반환하는 예제 코드이다. public Page&x3C;MemberTeamDto> sear
QuerydslJpa와 QClass
querydsljpa
Spring Data JPA가 기본적으로 제공해주는 CRUD 메서드 및 쿼리 메서드 기능을 사용하더라도 원하는 조건의 데이터를 수집하기 위해선 JPQL을 작성해야한다.JPQL로 간단한 로직을 작성하는데는 큰 문제가 없지만, 복잡한 로직의 경우 쿼리 문자열이 상당히 길어진다. 또, 정적 쿼리인 경우엔 어플리케이션 로딩 시점에 JPQL 문자열의 오타나 문법적인 오류를 발견할 수 있지만, 그 외는 런타임 시점에서 에러가 발생한다는 문제가 있다. 이러한 문제를 해결하기 위한 프레임워크가 바로 QueryDSL-jpa이다. QueryDSL을 사용하면 문자가 아닌 코드로 쿼리를 작성할 수 있기 때문에 컴파일 시점에 문법 오류를 쉽게 확인할 수 있고, 타입 안정성(type-safe)을 지키면서 동적인 쿼리를 편리하게
ReadOnlyQuery 최적화
jpa
JPA의 영속성 컨텍스트는 변경 감지를 위해 스냅샷 인스턴스를 보관하는 특징이 있다. 하지만 엔티티를 단순 조회하는 경우에는 컨텍스트에 있는 엔티티를 다시 꺼내오거나 수정할 필요가 없기 때문에 스냅샷 인스턴스를 저장하는 것이 메모리적으로 낭비이다. 이럴 경우 아래의 방법으로 메모리 사용량을 최적화할 수 있다. 스칼라 타입으로 조회 스칼라 타입은 영속성 컨텍스트가 관리하지 않기 떄문에, 엔티티가 아닌 스칼라 타입으로 조회하면 읽기 전용 쿼리에서 메모리를 절약할 수 있다. SELECT u.id, u.name, u.age FROM user u 읽기 전용 쿼리 힌트 사용 하이버네이트 전용 힌트인 org.hibernate.readOnly를 사용하면 엔티티를 읽기 전용으로 조회할 수 있다. 읽기 전용이므로
1차캐시
캐싱
캐시란 무엇일까? Cache는 간단히 말해서 나중의 요청에 대한 결과를 미리 저장했다가 빠르게 사용하는 것이다. 컴퓨터에서 중요한 메인 데이터들은 전원이 꺼져도 저장되는 SSD, HDD 등의 Secondary Memory에 저장된다. Secondary Memory에 저장된 데이터들은 장기적으로 안정적이게 저장될 수 있지만, 기술 한계상 데이터를 IO 하는 속도가 느리다. 그렇기 때문에 컴퓨터에서는 데이터 처리에 바로 필요한 데이터를 Main Memory인 RAM에 끌어놓거나, CPU에서 빠르게 접근할 수 있는 CPU Registers, Cache Memory의 형태로 저장하여 더 빠르고 쉽게 접근할 수 있도록 한다. 애플리케이션 서버(Spring JPA?)가 DB에 접근할 때를 예로 들어보면, DB에 연결
2차캐시
캐싱
애플리케이션에서 공유하는 캐시를 JPA는 공유 캐시(Shared Cache)또는 2차 캐시 (Second Level Cache, L2 Cache)라 부른다. 분산 캐시나 클러스터링 환경의 캐시는 애플리케이션보다 더 오래 유지 될 수도 있다. 2차 캐시를 적절히 활용하면 데이터베이스 조회 횟수를 획기적으로 줄일 수 있다. 1차캐시는 못하고 2차캐시는 할 수 있는 것 1차캐시는 영속성 컨텍스트에서 관리되는 캐시로, 트랜잭션이 시작하고 종료할 때 까지만 유지된다. 그렇기 때문에 같은 트랜잭션에서 한 엔티티를 여러번 가져와야할때 효과를 볼 수 있다. 하지만 만약에 여러 유저가 한 엔티티의 정보를 필요로 한다면 어떨까? 여러 요청들에서 공통적으로 같은 엔티티의 데이터가 필요한 경우에는, 1차캐시가 효용을 미치지 못한
영속성 컨텍스트
캐싱
영속성 컨텍스트랑 말 그대로 엔티티를 영속화(영구저장) 시켜주는 환경이다. 애플리케이션과 데이터베이스 사이에서 객체를 보관하는 가상의 데이터베이스(1차캐시) 역할을 한다. 엔티티 매니저를 통해 엔티티를 저장하거나 조회하면 엔티티 매니저는 영속성 컨텍스트에 엔티티를 보관하고 관리한다. 영속성 컨텍스트는 엔티티 매니저를 생성할 때 하나 만들어지고, 엔티티 매니저를 통해 영속성 컨텍스트에 접근하고 관리할 수 있다. 영속성 컨텍스트는 엔티티를 여러가지 상태로 저장한다. 엔티티의 생명주기 비영속(new/transient): 영속성 컨텍스트와 전혀 관계가 없는 상태 영속(managed): 영속성 컨텍스트에 저장된 상태 준영속(detached): 영속성 컨텍스트에 저장되었다가 분리된 상태 삭제(removed): 삭제
트랜잭션 전파 설정
jpa
Spring에서 사용하는 어노테이션 @Transactional은 해당 메서드를 하나의 트랜잭션 안에서 진행할 수 있도록 만들어주는 역할을 한다. 이때 트랜잭션 내부에서 트랜잭션을 또 호출한다면 스프링에서는 어떻게 처리하고 있을까? 새로운 트랜잭션이 생성될 수도 있고, 이미 트랜잭션이 있다면 부모 트랜잭션에 합류할 수도 있을 것이다. 진행되고 있는 트랜잭션에서 다른 트랜잭션이 호출될 때 어떻게 처리할지 정하는 것을 ‘트랜잭션의 전파 설정’이라고 부른다. 전파 설정 옵션 트랜잭션의 전파 설정은 @Transactional의 옵션 propagation을 통해 설정할 수 있다. 각 옵션은 아래와 같다. REQUIRED (default) 부모 트랜잭션이 존재한다면 부모 트랜잭션으로 합류하고, 부모 트랜잭션이 없다면 새
CSRF
springsecurity
CSRF(Cross site Request forgery)는 웹 애플리케이션의 취약점 중 하나로, 이용자가 의도하지 않은 요청을 통한 공격을 의미한다. 즉, 인터넷 사용자가 자신의 의지와 무관하게 공격자가 의도한 특정 행위를 웹사이트의 요청하도록 하여 간접적으로 해킹하도록 하는 것이다. 따라서, 스프링 시큐리티는 CSRF 공격을 방지하기 위한 기능을 가지고있다. @EnableWebSecurity 어노테이션을 붙이면 Referrer 검증, CSRF Token 사용 등의 기능이 활성화된다. 각 기능에 대해 간단하게 알아보자 Referrer 검증 서버단에서 request의 referrer을 확인하여 domain이 일치하는지 검증하는 방법이다. Spring Security CSRF Token 임의의 토큰을
@GroupSequence
validation
보통 WebRequest를 받을때, null이거나 비어있는 등의 유효하지 않은 값을 미리 걸러내기 위해 Sprign validation을 사용한다. 설정해둔 @NotNull, @Size, @Pattern 등 조건에 부합하지 못하면 MethodArgumentNotValidException이 발생하고, 이 에러를 적절히 처리하여 반환하는 방식이 많이 사용된다. 하지만 한 필드에 여러 검증을 넣게 되면, 그 검증에 순서가 부여되지 않아 무작위로 먼저 걸리는 조건의 에러가 반환된다. 그렇다면 이 에러 처리의 순서를 정해줘야 한다면 어떻게 해야할까? 즉, Null 체크를 먼저하고, 그다음 Size를 체크하고, 그다음 Pattern을 체크하는 방식으로 흐름을 지정하려면 어떻게 해야할까? 그런 경우 @GroupSeque
R2DBC
r2dbc
R2DBC는 Reactive Relational Database Connectivity의 줄임말이다. R2DBC는 관계형 데이터베이스 접근을 위해 구현해야 할 리액티브 API를 선언하는 스펙이다. JDBC는 완전한 블로킹 API이었고, RDBMS는 NoSQL에 비해 자체 리액티브 클라이언트를 가지고 있는 경우가 적어서 비동기 통신을 하기 힘들었다. 반면에 R2DBC는 Non-Blocking 관계형 데이터베이스 드라이버와 잘 동작하도록 하는 것을 목적으로 만들어졌다. 쿼리를 소켓에 기록하고 스레드는 응답이 수신될 때까지 다른 작업을 계속 처리하여 리소스 오버헤드를 줄이는 방식으로 적은 스레드, 하드웨어 리소스로 동시 처리를 제어할 수 있도록 한다. 하지만, R2DBC는 개념적으로 쉬운 것을 목표로 하므로, 기
Request 처리과정
webmvc
Spring Web MVC 에서 HTTP Request를 처리하는 핵심 클래스는 DispatcherServlet이란 클래스이다. 아 DispatcherServlet은 MVC 아키텍처로 구성된 프레젠테이션 계층을 만들 수 있도록 설계되어 있다. 서버가 브라우저 등의 HTTP 클라이언트로부터 요청을 받아 처리 후 응답하기까지의 과정을 알아보자. 1. DispatcherServlet의 요청 접수 자바 서버의 서블릿 컨테이너는 HTTP 프로토콜을 통해 들어오는 요청을 DispatcherServlet에 전달해준다. (이때, URL이나 확장자를 설정해주면 일부 요펑만 매핑되도록 설정할 수도 있다.) DispatcherServlet은 요청을 제일 먼저 받아 원하는 전처리 동작을 수행한 후 다음 클래스에게 일부
Ioc와 DI
기본원리
🍃 제어의 역전 IoC (Inversion of Control) 기존에는 클라이언트 구현 객체가 스스로 필요한 서버 구현 객체를 생성하고, 연결하고, 실행하는 프로그램. 즉, 구현 객체가 프로그램의 제어 흐름을 조정하는 프로그램이 많았다. 하지만 이런 방식은 코드의 재사용성과 유지보수성이 낮다. 하지만 그와 반대로 프로그램에 대한 제어 권한을 외부에서 가지고 있는 것을 제어의 역전(Ioc)이라고 한다. IoC는 객체지향성을 잃지 않고 유지보수성이 높은 코드를 만들 수 있게 해준다. (+ 프레임워크는 작성된 코드를 제어하고 대신 실행해주는 역할을 한다. Spring도 이와 같은 프레임워크의 일종이다.) IoC의 장점 애플리케이션 코드의 양을 줄일 수 있다. 클래스 간의 결합을 느슨하게 한다. 애플리케이
Reflection과 직렬화
기본원리
Reflection은 런타임에 동적으로 클래스들의 정보를 알아내고, 실행할 수 있는 것을 말한다. Reflection은 프로그래머가 데이터를 보여주고, 다른 포맷의 데이터를 처리하고, 통신을 위해 serialization(직렬화)을 수행하고, bundling을 하기 위해 일반 소프트웨어 라이브러리를 만들도록 도와준다. java와 같은 객체지향 프로그래밍언어에서 Reflection을 사용하면 컴파일 타임에 인터페이스, 필드, 메소드의 이름을 알지 못해도 실행중에 접글할 수 있다. 또, 멤버 접근 가능성 규칙을 무시하여 private 필드의 값을 변경할 수 있다. 직렬화 jackson은 java.lang reflection 라이브러리를 사용한다. 기본생성자가 있는 경우에는 _constructor.newInsta
기본원리
스프링 컨테이너(Spring Container) 스프링에서 DI를 이용하여 애플리케이션을 구성하는 여러 빈(Bean)들의 생명주기(Lifecycle)와 애플리케이션의 서비스 실행 등을 관리하며 생성된 인스턴스들에게 기능을 제공하는 것을 부르는 말이다. 프로그래머의 개입 없이도 컨테이너에 설정된 내용에 따라 빈을 알아서 참조하고 관리한다. 대표적으론 BeanFactory와 ApplicationContext 가 있다. BeanFactory 스프링 컨테이너의 최상위 인터페이스로서, 스프링 빈을 관리하고 조회하는 역할을 담당힌디. getBean() 을 제공한다. 지금까지 우리가 사용했던 대부분의 기능은 BeanFactory가 제공하는 기능이다. ApplicationContext BeanFactory 기능을 모두 상
선점 잠금과 비선점 잠금
기본원리
운영자 스레드와 고객 스레드는 같은 주문 애그리거트를 나타내는 다른 객체를 구하게 된다. 운영자 스레드와 고객 스레드는 개념적으로 동일한 애그리거트이지만 물리적으로 서로 다른 애그리거트 객체를 사용한다. 위 그림과 같은 상황에서 두 스레드는 각각 트랜잭션을 커밋할 때 수정한 내용을 DB에 반영하는데, 상태가 서로 충돌되기 때문에 애그리거트의 일관성이 깨진다. 이 순서의 문제점은 운영자는 기존 배송지 정보를 이용해서 배송 상태로 변경했는데 그 사이 고객은 배송지 정보를 변경했다는 점이다. 즉 애그리거트의 일관성이 깨지는 것이다. 이런 문제가 발생하지 않도록 하려면 다음 두 가지 중 하나를 해야한다. 운영자 배송지 정보를 조회하고 상태를 변경하는 동안 고객이 애그리거트를 수정하지 못하게 막는다. 운영자가 배
싱글톤
기본원리
웹 애플리케이션은 보통 여러 고객이 요청을 동시에 보내는데, 이럴 때 마다 새로운 객체를 생성해서 반환하는 것은 메모리 낭비가 너무 심하다. 그래서 고안된 것이 생성된 하나의 객체를 공유해서 사용하도록 설계한 ‘싱글톤 패턴’이다. 싱글톤 패턴은 이미 만들어진 객체를 재사용하기 때문에 객체를 생성하는 데 메모리와 시간을 쓰지 않아도 되니 아주 효율적이다! 하지만 싱글톤 패턴도 단점이 있다. 싱글톤 패턴의 문제점 싱글톤 패턴을 구현하는 코드 자체가 많이 들어간다. 의존관계상 클라이언트가 구체 클래스에 의존한다. DIP를 위반한다. 클라이언트가 구체 클래스에 의존해서 OCP 원칙을 위반할 가능성이 높다. 테스트하기 어렵다. 내부 속성을 변경하거나 초기화 하기 어렵다. private 생성자로 자식 클래스를 만들기
웹서버와 WAS
was
웹 서버(Web Server) 웹 서버란 HTTP 프로토콜을 기반으로 클라이언트가 웹 브라우저에서 어떠한 요청을 하면 그 요청을 받아 정적 컨텐츠를 제공하는 서버이다. 정적 컨텐츠란 단순 HTML 문서, CSS, 이미지, 파일 등 즉시 응답 가능한 컨텐츠이다. 이때 웹 서버가 정적 컨텐츠가 아닌 동적 컨텐츠를 요청받으면 WAS에게 해당 요청을 넘겨주고, WAS에서 처리한 결과를 클라이언트에게 전달하는 역할도 해준다. 이러한 웹 서버에는 Apache, NginX등이 있다. WAS(Web Application Server) WAS란 DB 조회 혹은 다양한 로직 처리를 요구하는 동적 컨텐츠를 제공하기 위해 만들어진 Application 서버이다. HTTP 프로토콜을 기반으로 사용자 컴퓨터나 장치에 애플리케이션을
netty의 thread 모델
netty
이벤트 루프란 이벤트를 실행하기 위한 무한루프 스레드를 말한다. 위의 그림과 같이 객체에서 발생한 이벤트는 이벤트 큐에 입력되고 이벤트 루프는 이벤트 큐에 입력된 이벤트가 있을 때 해당 이벤트를 꺼내서 이벤트를 실행한다. 이것이 이벤트 루프의 기본 개념이다. 이벤트 루프는 지원하는 스레드 종류에 따라서 단일 스레드 이벤트 루프와 다중 스레드 이벤트 루프로 나뉜다. 이것을 reactor pattern이라 부르기도 한다. single thread event loop 현재는 다중 코어나 CPU를 장착한 시스템이 일반적이므로 최신 애플리케이션은 시스템 리소스를 효율적으로 활용하기 위해 정교한 멀티스레딩 기법을 이용하는 경우가 많다. 자바 초창기의 멀티스레딩 체계는 동시 작업 단위를 실행하기 위해 필요할 때마다 새
webFlux와 netty
netty
Spring MVC는 기본적으로 블럭킹이고 동기방식을 사용한다. 비동기 처리 기능이 스프링 프레임워크 3에서 추가되어 지원된다고 하지만, 서블릿은 응답을 기다리는 동안 pool의 스레드들은 여전히 지연시킬 수 있기 때문에 전체 stack이 reactive 해야 하는 요구를 충족시킬 수 없다. 이러한 요구사항에 맞추어 스프링 프레임워크5에 도입된 대안적인 모듈이 바로 WebFlux이고, 웹 요청을 reactive 하게 다루는 데에 초점이 맞추어져 있다. 기존의 서블릿 기반의 Spring Boot는 Tomcat을 기반으로 동작한다. 반면 Spring Boot WebFlux는 여러 가지를 고를 수 있는데, Default로 Netty를 사용한다. Netty를 사용하는 이유는 tomcat은 요청 당 하나의 스레드가