Time Business Logic Testing on Spring (Kotlin, Java)

이미지
올해에 너무 글쓰는 것을 소홀히 했던것을 반성하며 남은 한 달 동안 글을 몇 개라도 조금 써보려고한다! Java, Kotlin 기반 Spring 프레임워크 환경에서 개발을 하다보면 시간과 관련된 로직이 필요할 수 있다. 이 때 어떻게 해결하면 좋을 지 테스트 코드는 어떻게 구성하면 좋을지 정리하려고 한다. 예를 들어, 특정 기간동안만 액션이 가능한 요구사항이 있다고 가정하자. 해당 기간이 시작하기전에 액션을 진행하지 못하도록 막아야 되고, 기간인 경우 가능하도록 그리고 기간이 끝났을 때 더이상 액션이 불가능하도록 막아야 한다. 이 예제를 바탕으로 간단한 샘플 코드를 정리해보았다. - Kotlin - Spring Boot 2.7.5 - Junit 5 우선 아래와 같이 zoneId 를 인자로 받는 now 함수를 작성하였다. CHANGEABLE_CLOKC 이 null 이 아닐경우 해당 Clock 을 기준으로 LocalDateTime 인스턴스를 생성한다. 그리고 now 를 테스트하기 위한 코드. CHANGEABLE_CLOCK 이 null 인 경우와 null 이 아닌 경우 두 가지 테스트 케이스이다. null 인경우에는 zoneId 에 따라서 인스턴스를 생성하기 때문에 빈 인자인 경우 UTC 기준, Kst ZoneId 제공시 kst 시간 인스턴스를 생성하여 9시간 차이를 확인하는 코드이다. 두번 째는 Clock 을 2025 년 1월 1일로 설정하여 now 함수 호출 시 CHANGEABLE_CLOCK 기준으로 인스턴스를 생성하게 되어있다. 자 그렇다면 기간과 관련된 로직과 해당 로직을 테스트하는 코드를 작성해보자. 아래와 같이 property 에서 기간을 주입받는 Service 를 test code 를 작성해보자. ReflectionTestUtils 를 통해서 Mocking 하는 service 에 기간을 주입한다. 그리고 CHANGEABLE_CLOCK 을 통해서 now() 함수가 기간에 속할 때와 아닐 때로 지정하여서 올바른 값을 반환하는지 검증한다. 또 다른 방법중 하...

Multiple Java In My Mac

이미지
 Java 언어를 통해서 개발을 하다보면 프로젝트마다 Java Version 이 달라서 스위칭하는 데에 꽤나 번거롭다. 조금이나마 간단하게 해결하기 위해서 이 글을 정리한다. 우선 나의 로컬에는 아래와 같이 3가지 version 의 JDK 가 공존한다. - Zulu 13 - Amazon Corretto 11 - Amazon Corretto 8 현재 설정된 JAVA_HOME 아래와 같이 지정한 alias 를 통해서 JAVA_HOME 을 편하게 변경해보자. 먼저 .zshrc 또는 .bash_profile 을아래와 같이 작성한다. version 에 따른 JAVA HOME 변수를 할당하고 각각의 alias 를 통해서 JAVA_HOME 을 switch 시킬 수 있도록 한다. 이외에도 jenv 를 통해서 관리할 수 있다. https://www.jenv.be/

String is Immutable In Java

이미지
개요  Java 에서 String 을 어떻게 다루고 있는지 정리해보겠다. Java 에서 String 은 Immutable 로 즉 불변이다. Java 의 아버지 제임스 고슬링은 "I would use an immutable whenever i can." 이라고도 말했다. 어떠한 이유에서 이러한 말을 했는지 알아보자. Immutable 먼저 Immutable 이란 무엇일까? 불변이란 생성 후에 내부 상태를 변경할 수 없다는 것을 나타낸다. 다시 말해, 생성 후 객체를 변수에 할당하고 나면 해당 객체 참조를 변경하거나 내부 상태를 변경할 수 없고 다시 생성해야지 해당 참조를 변경할 수 있다. Why String is Immutable? 바로 caching, security, synchronization and performance 이다. 차례대로 확인해보자. String pool String pool 은 JVM 에 의해서 String 들이 저장되는 특수한 메모리 영역이다. literals 로 String 변수를 할당하게 되면 다른 변수일지라도 같은 내용일 경우 String pool 에 있는 같은 객체를 참조하게 된다. 이를 통해서 heap 영역을 절약할 수 있고 재사용성을 높인다. s1 과 s2 는 literals 로 String 을 생성했기에 s1 변수가 할당 될 때 String pool 에 "hello world" 가 생성되고 s2 변수가 할당될 때 기존에 s1 이 가르키고 있는 String pool 의 "hello world" 를 참조하게 된다. 반대로 new String() 을 통해서 생성한 String 은 같은 참조를 가르키지 않는다. 항상 새로운 객체를 생성하게 된다. Security Java Application 에서 String 은 username, password, connection URLs, network connections, etc. 와 같이 민감한 자료를 저장하는데 사용된다. 따라서 보안...

I need to know a little Garbage Collection

이미지
개요  프로그래밍 언어에는 2가지 언어가 있다. Managed 언어와 Unmanaged 언어로 구분된다. 이 둘의 가장 큰 차이점은 개발자가 직접 메모리를 할당하고 해제하는 관리 여부로 결정된다.  대표적인 Unmanaged 언어로 C, C++ 이 있고, Managed 언어로는 Java, Python, Go, C# 등이 있다. 이번글에서는 알아서 memory 를 관리해주는 Garbage Collection 에 대해서 정리해보려고한다. 언어마다 Garbage Collection 알고리즘이나 기법이 다르다. 이 글에서 다루고자 하는 언어는 Java 이고 JVM 이다. What? Heap 영역에서 어떤 object 가 사용중인지 아닌지 확인하고 사용하지 않는 object 는 삭제한다. 사용중인 object 는 referenced object 로 program 에서 해당 object 에 대한 pointer 를 유지하고 있는 것을 의미한다. 사용하지 않는 object 는 unreferenced object 로 더 이상 program 에서 pointer 를 유지하고 있지 않는 것을 의미한다. 따라서 unreferenced object 의 memory 를 회수할 수 있다. C 나 C++ 은 수동으로 memory 를 allocate 하고 deallocate 한다. Java 에서는 Garbage Collector 에 의해서 자동으로 관리된다.  첫 번째 : Marking Garbage Collector 가 memory 의 사용여부를 확인하는 작업이다. referenced objects 들은 파란색이다. Unreferenced objects 는 주황색이다. 모든 objects 는 Marking 단계에서 scan 작업을 거친다. 만약 전체 시스템의 모든 objects 를 scan 해야 한다면, 이 작업은 시간이 많이 드는 작업이다. 두 번째 - 1 : Normal Deletion Normal deletion 은 unreferenced objects 지우지...

I need to know a little JVM

이미지
개요 현재 개발자 채용시장에 있어서 Java 가 가장 영향력있는 언어이지 않을까 생각한다. Java 가 영향력이 큰 이유는 아마도 ecosystem 덕분이지 않을까 생각이 든다. 최근에 여러 모던 언어들이 등장하고 있지만, 여전히 Java 에 입지는 굉장히 강력하다. 물론 Kotlin 이라는 언어가 등장하면서 판도의 흐름이 보이고 있다. 둘의 공통점은 JVM 기반 언어라는 점이다. (물론 Kotlin/JS 는 다른이야기 이지만) 이외에도 Scala, Clojure, Groovy 등등 JVM 기반 언어들이 많다. 이번글에서는 JVM 을 high-level 구조를 정리해보려고 한다. 해당 구조는 Java 8 을 기준으로 정리를 했다. 현재 LTS 로 Java 17 까지 출시가 되었으며 변경사항이 있는 것을 참고해야 한다. JVM 구조 ClassLoader Subsystem JVM 언어의 철학 중 하나가 Write Once Run Anywhere 이다. compile 시 하드웨어가 바로 이해할 수 있는 low-level 로 번역이 되는 것이 아닌 JVM 이 이해할 수 있는 byte code 로 변환된다. 바로 class 파일 포맷이다. ClassLoader 의 역할이 바로 compile 된 class 파일들을 runtime 에 동적으로 load 하는 역할을 한다. ClassLoader 로 인해서 runtime system 은 machine 의 file 및 filesystem 을 알 필요가 없다. 모든 class 파일은 한번에 load 되는 것이 아니다. 필요한 시기에 필요한 class 파일을 요청하며 이에따라 요청받은 ClassLoader 가 역할을 한다. 또한 ClassLoader 는 하나가 아니다. 요청한 class path 나 type 에 따라 동적으로 ClassLoader 가 선택된다. ClassLoader 는 3가지 종류가 있다. - Bootstrap ClassLoader : java class 가 아닌 c/c++ 로 이루어져있다. JDK interna...

Statement and PreparedStatement

이미지
이번글에서는 JDBC API Statement 와 PreparedStatement 의 차이점에 대해서 정리하려고한다. Java Database Connectivity API 는 Java 를 사용하여 data access 를 할 수 있도록 제공해준다. RDBMS 뿐만 아니라 spreadsheets 와 flat files 도 가능하다. JDBC API 는 2개의 패키지로 구성된다. - java.sql - javax.sql Statement String-based query 를 실행시킨다. parameter 대신 static SQL 을 처리하기 좋다. runtime 에 오직 한 번만 실행시킬 DDL 을 사용하기 적합하다. Binary Data Read / Write 작업에 사용이 불가능하다. Binary Protocol 이 사용되지 않는다. SQL Injection 에 취약하다. PreparedStatement parameterized query 를 기반으로 한다. runtime 에 parameter 를 다루고 여러번 수행되는 어떤 종류의 Query 도 처리하기 좋다. Dynamic query 를 처리하기 좋다. Binary Data Read / Write 작업이 가능하다. Binary Protocol 사용이 가능하다. 둘의 가장 큰 차이점은 precompiled 에 따른 성능과 보안 측면에서 SQL injection 방지이다. 참조 https://docs.oracle.com/javase/8/docs/technotes/guides/jdbc/ https://www.baeldung.com/java-statement-preparedstatement https://www.geeksforgeeks.org/difference-between-statement-and-preparedstatement/ https://docs.oracle.com/javase/tutorial/jdbc/basics/prepared.html#:~:text=As%20a%20result%2C%20the%20...

About Spring AOP JDK Dynamic Proxy and CGLIB Dynamic Proxy

이미지
개요  Spring Framework 를 사용할 때 AOP 는 필수라고 말해도 과언이 아니다. Logging, Transaction Management, Caching, Security 등등 에서 주로 사용된다. 그렇다면 Spring AOP 는 어떻게 동작할까? 이번 글에서 정리를 해보려고 한다.  Spring 에서 AOP 는 JDK Dynamic Proxy 혹은 CGLIB Dynamic Proxy 를 사용하여 Proxy 를 생성하여 관리한다.  Proxy target object 가 하나 이상의 interface 를 구현하는 경우에는 JDK Dynamic Proxy 가 사용된다. 반대로 target object 가 interface 를 구현하지 않는다면 CGLIB proxy 가 생성된다. 하지만 proxy-target-class=true 로 설정한다면 interface 를 구현하더라도 CGLIB proxy 가 사용된다. CGLIB Proxy 를 사용할 때 고려해야 할 몇가지가 있다. - final method 는 overriding 이 불가능하기 때문에 advice 적용이 불가능하다.  - target class 가 final 일 경우 불가능하다. - Spring 3.2 version 전의 경우 CGLIB 와 관련된 jar 를 classpath 에 추가해주어야 한다. 3.2 version 부터는 org.springframework.cglib 로 repackaged 되어 spring-core jar 안에 포함이 되었다. - Spring 4.0 version 전의 경우 proxy target object 의 생성자는 두 번 호출되었다. 또한 기본 생성자가 필수였다. 4.0 version 이후부터는 Objenesis 를 통해서 proxy instance 가 생성될 때 더이상 생성자가 두 번 호출되지 않게 되었다. 일반적이지 않은 경우이지만 4.0 version 전에서는 proxy target object 의 생성자에 주요한 로직을...