2023-02-06-TIL
2023-02-06-TIL
Today I Learned
권한에 따라 다른 응답을 내려주는 방법과 접근 제어 모델(RBAC, ACL)을 정리하고, 스레드 풀 거절 예외, Java 미디어 처리 라이브러리, 컨테이너 안의 JVM 힙 설정, 패키지 구조를 찾아봤다.
Showing Different Response Depending on the Role and Privilege
스프링 시큐리티를 사용한다면 설정을 통해서 응답할 필드를 지정할 수 있다. 또한, 권한 별로 컨트롤러에 접근 가능여부를 설정할 수도 있다. 필드에 일일이 @JsonView 같은 애너테이션을 다는것 보다는 깔끔하게 컨트롤러를 분리하는 것이 나을것 같다. 다만, 그렇게 되면 권한 별로 분리되어야 하는 분기가 서비스, 레파지토리 계층까지 전이가 될 수 있는데, 그때마다 메서드를 분리할 것인지, 아니면 조건문으로 분기할 것인지를 또 고민해봐야 한다.
선택지를 정리하면 세 가지다.
@JsonView: 필드마다 뷰 클래스를 지정하고, 요청한 사용자의 역할에 맞는 뷰로 직렬화한다. Baeldung 글은 역할과 뷰를 매핑해 응답 필드를 거르는 방법을 보여 준다. 응답 클래스는 하나로 유지되지만 필드와 역할의 관계가 애너테이션에 흩어진다.- 역할별 응답 DTO:
AdminUserResponse,UserResponse처럼 응답 타입을 나눈다. 타입만 보고 무엇이 노출되는지 알 수 있다. 역할별 컨트롤러(또는 엔드포인트):
/admin/**처럼 경로를 나누고 Spring Security의 URL 규칙이나@PreAuthorize로 접근을 막는다. 위에 적은 대로 분기가 하위 계층까지 번지지 않도록, 서비스는 공통으로 두고 응답 조립만 나누는 방식을 함께 고민해야 한다.- https://stackoverflow.com/questions/30894333/show-different-web-pages-and-elements-depending-on-the-user-role-and-privilege
- https://www.baeldung.com/spring-security-role-filter-json
- https://stackoverflow.com/questions/64378312/different-response-based-on-logged-user-role
RBAC(Role-Based Access Control)
Okta 문서는 RBAC과 ABAC의 핵심 차이를 접근 권한을 부여하는 방식으로 설명한다. RBAC은 역할(role) 단위로 권한을 주고, ABAC(Attribute-Based Access Control)은 사용자 속성, 대상 객체의 속성, 행동, 환경 조건 같은 특성을 조합해 접근을 판단한다. RBAC은 구조가 단순해 대부분의 조직에 맞지만, “같은 부서의 문서만, 근무 시간에만”처럼 조건이 세밀해지면 역할이 폭발적으로 늘어나 ABAC이 필요해진다.
- https://www.okta.com/kr/identity-101/role-based-access-control-vs-attribute-based-access-control/
ACL
ACL(Access Control List)은 자원마다 접근 가능한 주체와 허용 작업을 목록으로 붙이는 방식이다. 링크한 글은 라우터 같은 L3 장비의 ACL, 즉 패킷의 주소와 포트 조건에 따라 전송을 허용하거나 거부하는 규칙 목록을 다룬다. 애플리케이션에서는 Spring Security ACL처럼 도메인 객체 하나하나에 권한을 붙이는 용도로 쓰인다.
- https://peemangit.tistory.com/33
JUnit5 @ExtendWith instead of @RunWith
JUnit 4의 @RunWith는 테스트 러너 하나를 통째로 바꾸는 방식이라 한 클래스에 하나만 지정할 수 있었다. JUnit 5(Jupiter)는 러너 대신 확장(Extension) 모델을 쓰고, JUnit 5 사용자 가이드는 @ExtendWith를 확장을 선언적으로 등록하는 애너테이션으로 설명한다. 여러 확장을 함께 등록할 수 있으며, Spring의 @SpringBootTest는 이미 @ExtendWith(SpringExtension.class)를 포함하고 있어 따로 붙일 필요가 없다. Mockito는 MockitoExtension을 쓴다.
- https://cjred.net/2020-04-30-junit-5-runwith-extendwith/
RejectedExecutionException
ThreadPoolExecutor Javadoc에 따르면 새 작업은 Executor가 종료되었을 때, 또는 최대 스레드 수와 작업 큐 용량이 모두 유한하고 포화되었을 때 거절된다. 거절된 작업은 RejectedExecutionHandler가 처리하며, 기본 정책인 AbortPolicy는 런타임 예외인 RejectedExecutionException을 던진다. 다른 정책으로는 호출한 스레드가 직접 실행하는 CallerRunsPolicy(작업 제출 속도를 자연스럽게 늦춘다), 조용히 버리는 DiscardPolicy, 가장 오래된 작업을 버리는 DiscardOldestPolicy가 있다. Spring의 ThreadPoolTaskExecutor에서도 queueCapacity와 maxPoolSize를 정할 때 이 정책을 함께 정해야 한다.
- https://sgdev.tistory.com/17
Spotify ERD
음악 스트리밍 서비스의 데이터 모델을 참고하려고 모은 자료다. 핵심은 아티스트, 앨범, 트랙, 플레이리스트, 사용자 사이의 관계다. 트랙과 아티스트(피처링), 플레이리스트와 트랙은 다대다라서 연결 테이블이 필요하고, 플레이리스트의 트랙에는 순서와 추가 시각 같은 속성이 붙는다. DBA StackExchange 질문은 아티스트와 앨범의 관계를 어떻게 표현할지를 다루고, drawsql의 Koel 템플릿은 자체 호스팅 음악 스트리밍 서버 Koel의 스키마로, 아티스트, 앨범, 곡, 플레이리스트 공유와 협업자, 재생 횟수까지 포함한다.
- https://www.timjoo.com/spotify
- https://blog.bruggen.com/2021/08/
- https://dba.stackexchange.com/questions/235289/how-to-represent-the-relationship-between-artists-and-albums-in-an-entity-relati
- https://drawsql.app/templates/koel
- https://www.youtube.com/watch?v=ks-CS41AiQs
Xuggler vs FFmpeg
Xuggler는 FFmpeg을 Java에서 쓰도록 감싼 라이브러리로, 네이티브 라이브러리를 함께 설치해야 한다. GitHub 저장소 설명에는 “DEPRECATED”가 붙어 있어 새로 쓰기에는 적합하지 않다. 대안은 FFmpeg 바이너리를 프로세스로 실행하고 결과를 읽는 방식이나, 다른 FFmpeg 래퍼 라이브러리다. 재생 시간이나 코덱 같은 메타데이터만 필요하면 FFmpeg 문서의 ffprobe가 멀티미디어 스트림 정보를 사람이 읽거나 기계가 파싱할 수 있는 형식으로 출력하므로, JSON 출력을 받아 파싱하면 된다.
1
ffprobe -v quiet -print_format json -show_format input.mp3
- https://stackoverflow.com/questions/23784422/java-xuggler-play-video-while-combining-an-mp3-audio-file-and-a-mp4-movie
- https://www.javacodegeeks.com/xuggler-tutorials
- https://byul91oh.tistory.com/418
- https://github.com/artclarke/xuggle-xuggler
- https://groups.google.com/g/xuggler-users/c/lInnch7Q3yI?pli=1
- https://stackoverflow.com/questions/8641238/xuggle-or-ffmpeg-newbie
- https://www.wowza.com/community/t/a-confusing-array-of-differences-when-using-xuggler/37228
- https://json2video.com/how-to/ffmpeg-course/ffmpeg-wrappers.html
- https://ffmpeg.org/ffprobe.html
Java Heap Size Inside a Docker Container
컨테이너에서 JVM을 실행할 때는 힙 크기를 고정값(-Xmx)으로 줄 수도 있고, 컨테이너 메모리 한도에 대한 비율로 줄 수도 있다. java 명령 문서에 따르면 -XX:MaxRAMPercentage는 JVM이 판단한 가용 메모리 중 Java 힙에 쓸 최대 비율이고 기본값은 25%다. 컨테이너 지원(UseContainerSupport)이 켜져 있으면 JVM이 호스트 전체 메모리가 아니라 컨테이너의 메모리 한도를 기준으로 계산하므로, 컨테이너 메모리를 바꿀 때 힙 설정을 함께 고칠 필요가 없다는 장점이 있다.
옵션을 이미지 밖에서 주입하려면 환경 변수를 쓴다. Oracle 문서는 JAVA_TOOL_OPTIONS가 JVM이 시작할 때 읽혀 명령줄 옵션을 보강하는 데 쓰인다고 설명한다. JAVA_OPTS는 JVM이 직접 읽는 변수가 아니라 실행 스크립트(Tomcat 등)가 관례적으로 java 명령에 붙여 주는 변수라는 점이 다르다.
1
docker run -m 1g -e JAVA_TOOL_OPTIONS="-XX:MaxRAMPercentage=75.0" my-app
- https://www.baeldung.com/ops/docker-jvm-heap-size
- https://alvinalexander.com/blog/post/java/java-xmx-xms-memory-heap-size-control/
- https://stackoverflow.com/questions/417152/how-do-i-set-javas-min-and-max-heap-size-through-environment-variables
- https://stackoverflow.com/questions/28327620/difference-between-java-options-java-tool-options-and-java-opts
- https://docs.oracle.com/javase/8/docs/platform/jvmti/jvmti.html#memory
- https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/envvars002.html
Package Structure
지난번에 이어 패키지 구조 자료를 더 모았다. 계층형과 도메인형의 장단점은 그대로이고, 추가로 확인한 점은 도메인형 안에서도 상위 구분을 두는 방식이다. cheese10yun의 spring-guide는 domain 아래에 도메인별로 api, application, dao, domain, dto, exception을 두고, global에는 공통 요청·응답, 설정, 에러 처리, 유틸을, infra에는 이메일이나 SMS 같은 외부 연동을 둔다. O’Reilly의 Software Architecture Patterns 1장은 계층형 아키텍처 패턴 자체를 설명한다.
- https://www.inflearn.com/questions/16046/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%8F%B4%EB%8D%94-%EA%B5%AC%EC%A1%B0%EC%99%80-%EA%B0%95%EC%9D%98-%EC%9D%BC%EC%A0%95%EC%97%90-%EA%B4%80%ED%95%98%EC%97%AC-%EC%A7%88%EB%AC%B8%EC%9D%B4-%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4
- https://junjunrecord.tistory.com/m/133
- https://www.slipp.net/questions/36
- https://joanne.tistory.com/175
- https://groups.google.com/g/ksug/c/3Xg1Y8rsExQ
- https://freedeveloper.tistory.com/245
- https://github.com/cheese10yun/spring-guide/blob/master/docs/domain-guide.md
- https://github.com/cheese10yun/blog-sample/tree/master/lombok
- https://umbum.dev/1206
- https://cheese10yun.github.io/spring-guide-directory/
- https://velog.io/@haron/Spring-Project-Structure
- https://www.geeksforgeeks.org/spring-boot-code-structure/
- https://stackoverflow.com/questions/40902280/what-is-the-recommended-project-structure-for-spring-boot-rest-projects
- https://www.javaguides.net/2019/01/standard-project-structure-for-spring-boot-projects.html
- https://medium.com/sahibinden-technology/package-by-layer-vs-package-by-feature-7e89cde2ae3a
- https://www.oreilly.com/library/view/software-architecture-patterns/9781491971437/ch01.html
- https://www.techyourchance.com/popular-package-structures/
Application Architecture
제목대로 엔티티, 도메인 모델, DTO를 왜 따로 두는지를 다룬 글이다. 엔티티는 DB 테이블과 매핑되는 영속성 모델, 도메인 모델은 비즈니스 규칙을 담는 모델, DTO는 계층이나 시스템 사이에서 데이터를 옮기는 모델이다. 작은 서비스에서는 엔티티가 도메인 모델 역할까지 겸하는 경우가 많지만, API 응답에 엔티티를 그대로 노출하면 DB 구조 변경이 API 변경으로 번지므로 최소한 DTO는 분리하는 것이 좋다.
- https://itzone.com.vn/en/article/entity-domain-model-and-dto-why-so-many/
댓글
아직 댓글이 없습니다