728x90

일을 하다보면 늘 시간과 관련하여 파싱 혹은 생성할 일이 많다.

자바에서 날짜 혹은 시간을 사용하는 방법을 간략하게나마 정리하기 위해 작성을 하였다.

 

타임존

타임존은 동일한 로컬 시간을 따르는 지역을 의미한다.
보통 구각별로 고유 타임존을 사용하며, 면적이 넓은 나라는 지역 별로 다른 타임존을 사용한다.

 

타임존의 종류 

  • GMT(GreenWich Mean Time)
한국의 타임존은 보통 GMT +09:00으로 표현된다. 영국 그리니치 천문대 기준으로 하는 태양 시간.
  • UTC
지구 자전 주기의 흐름이 늦어지고 있는 문제를 해결한 시간. GMT를 대체하기 위한 새로운 표준. GMT와 아주 미세한 차이인데, 소프트웨어에서 사용할 때는 UTC가 더 정확한 표현이다.
  • Offset
UTC+09:00에서 +09:00의 의미는 UTC 기준 시간보다 9시간 빠르다는 의미이다. 즉, UTC 12시이면, 한국시간으로 9시라는 것이다. 이처럼, UTC와의 차이를 나타낸 것을 Offset이라고 한다.
보통 국가나 지역마다 자신이 사용하는 타임존에 대해 고유 이름을 부여한다. 대한민국의 타임존은 KST(Korea Standard Time)이라고 부른다. KST = UTC+09:00 이라고 이해하면 쉽다.
한 지역의 타임존은 하나 이상의 오프셋을 갖는다. 해당 지역의 정치/경제적 상황에 따라 계속해서 달라질 수 있다.
  • ISO 8610
날짜와 시간 관련된 데이터 교환을 다루는 국제 표준. 국제 표준화 기구(ISO)에 의해 공포되었고, 1988에 처음으로 공개되었다.

 

ex) 2021-07-19T17:40:00+09:00

위 시간을 해석해 보면

  1. Z or +00:00 : UTC 기준시를 나태내는 표시
  2. T : 날짜 뒤에 시간이 오는 것을 표시해주는 문자
  3. 시간(17:40:00) : 시:분:초 형태. 언어에 따라 초 뒤에 소수점 형태로 milliseconds가 표시되기도 한다.
  4. Timezone Offset : 시간 뒤에 +/-시간:분 형태 나타냄
  5. Z or +00:00 : UTC 기준시를 나태내는 표시
// 로컬 시간
2021-07-19T17:40:00.000

*//UTC(GMT)*

2021-07-19T17:40:00.000Z

*//로컬 시간을 의미하면서 UTC(GMT) 대비 +09:00 임을 의미*

2021-07-19T17:40:00.000+09:00

 

java1.8 이전 date

java.util패키지에 Date 클래스가 존재한다. JDK1.0부터 제공되어온 클래스이다. JDK1.1에서는 Calendar 클래스도 나왔다. Calendar 추가 후 Date의 대부분이 deprecated 됐다.

형식화 클래스
java.text 패키지에 포함되어 있으며, 숫자, 날짜, 텍스트 데이터를 일정한 형식에 맞게 표현할 수 있다. 객체지향적 설계하여 표준화했다.

 

1.8 이전 가장 자주쓰던 SimpleDateFormat  아래와 같다. 

SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");

 

 

1.8 이후 Java.time 패키지

기존 java에 있던 Date, Calendar 클래스의 단점을 해소하기 위해 JDK1.8부터 java.time 패키지가 추가되었다.

java.time : 날짜와 시간을 다루는데 필요한 핵심 클래스들을 제공
java.time.chrono : 표준(ISO)이 아닌 달력 시스템을 위한 클래스들을 제공
java.time.format : 날짜와 시간을 파싱하고, 형식화하기 위한 클래스들을 제공
java.time.temporal : 날짜와 시간의 필드(field)와 단위(unit)를 위한 클래스들을 제공
java.time.zone : 시간대(time-zone)와 관련된 클래스들을 제공


가장 큰 특징은 String 클래스처럼 불변(Immutable) 하다는 것. 그래서 항상 새로운 객체를 반환한다.

 

 

핵심 클래스

  • LocalDateTime
Zone구분 없이 Local 시간을 표시

시간표현 - LocalTime class

날짜표현 - LocalDate class

둘다 표현 시, LocalDateTime을 사용
  • ZondDateTime
Zone을 구분하는 시간을 나타낸다. 2021-07-19T17:40:00.000++09:00[Asia/Seoul]

LocalDateTime + 시간대 : ZonedDateTime 클래스
ZoneId zoneId = ZoneId.of("Asia/Seoul");
//ZoneId zoneId = ZoneId.of("America/New_York");
ZonedDateTime zoneDateTime = dateTime.atZone(zoneId);
System.out.println(zoneDateTime); // 2021-07-19T17:40:00.000+09:00[Asia/Seoul]
  • ZoneOffset
UTC로부터 얼만큼 떨어져있는지 ZoneOffset으로 표현한다. 서울은 +9, 미국 뉴욕은 -4이다.
ZoneOffset krOffset = ZonedDateTime.now().getOffset();
int krOffsetInSec = KrOffset.get(ChronoField.OFFSET_SECONDS); // 32400
  • OffsetDateTime
ZonedDateTime은 ZoneId로 구역을 표현하지만, ZoneOffset을 사용하는 것은 OffsetDateTime이다. ZoneId는 일광절약시간 같은 시간대 관련 규칙을 포함하지만 ZoneOffset은 시간의 차이로만 구분한다. 그래서 컴퓨터 통신 간에는 계절별로 시간을 뺏다 더했다 하는 것 보다 안전한 OffsetDateTime을 이용한다.
  • Parsing & Format
java.time.format 패키지에 들어있는 DateTimeFormatter와 parse 메서드를 사용한다.
//Date To String 
LocalDate localDate = LocalDate.of(2021, 7, 19);
String localDateString = DateTimeFormatter.ISO_LOCAL_DATE.format(localDate); // "2021-07-19"
String localDateString = localDate.format(DateTimeFormatter.ISO_LOCAL_DATE); // "2021-07-19"
//String To Date
LocalDateTime localDateTime = LocalDateTime.parse("2021-07-19T00:00:00");

위 예시 말고도 날짜를 더하고 비교하는  여러가지가 더 있지만 이정도로 개념적인 정리는 될듯 하다.

 

 

728x90
728x90

 

 

정적 팩토리 메서드와 팩터리 메서드 디자인 패턴과는 다르다.

 

장점

1. 이름을 가질 수 있다.
2. 호출될 때마다 인스턴스를 새로 생성하지는 않아도 된다. 
3. 반환 타입의 하위 타입 객체를 반환할 수 있는 능력이 있다. 
4. 입력 매개변수에 따라 매번 다른 클래스의 객체를 반활할 수 있다. 
5. 정적 팩터리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다. 

 

단점

1. 상속을 하려면 public이나 protected생성자가 필요하니 정적 팩터리 메서드만 제공하면 하위 클래스를 만들 수 없다.
2. 정적 팩터리메서드는 프로그래머가 찾기 어렵다.

 

정적 팩터리 메소드 명명방식

from - 매개변수를 하나 받아서 해당 타입의 인스턴스를 반환하는 형변환 메서드
of- 여러 매개변수를 받아 적합한 타입의 인스턴스를 반환하는 집계메서드
valueOf - from과  of의 더 자세한 버전 
instance OR getInstance - (매개변수를 받는다면 ) 매개변수로 명시한 인스턴스를 반환하지만, 같은 인스턴스임을 봊아하지는 않는다. 
create OR newIstnace - instance 혹은 getInstance와 같지만, 매번 새로운 인스턴스를 생성해 반환함을 보장한다.
getType - getInstance와 같으나 생성할 클래스가 아닌 다른 클래스에 팩터리 메서드를 정의할 때 쓴다. "Type"은 팩터리메서드가 반환할 객체의 타입이다. 
newType - newInstance와 같으나, 생성할 클래스가 아닌 다른 클래스에 팩터리 메서드를 정의할 때 쓴다. "Type"은 팩터리메서드가 반환할 객체의 타입이다. 
type - getType과 newType의 간결한 버전

 

핵심정리

정적 팩터리 메서드와 public 생성자는 각자으 ㅣ쓰임새가 있으니 상대적인 장단점을 이해하고 사용하는 것이 좋다. 그렇다고 하더라도 정적 팩터리를 상용하는게 유리한 경우가 더 많으므로 무작정 public 생성자를 제공하던 습관이 있다면 고치자.
728x90
728x90

재직중인 회사에 이전에 작업된 부분중에 테스트 필터링이 적용되어 있는 부분을 확인하였다. 이 부분에 대하여 공부 겸 정리를 할려고한다.

 

Tag annotation

공식문서의 설명은 이렇다.

Tags are a JUnit Platform concept for marking and filtering tests. The programming model for adding tags to containers and tests is defined by the testing framework. For example, in JUnit Jupiter based tests, the @Tag annotation (see Tagging and Filtering ) should be used.

즉, Tag 어노테이션의 목적은 테스트에 어떤 테스트인지 표기하는 동시에 필터링하는 것입니다.

 

Tag 어노테이션 사용 사례

 

아래는 여러개를 동시에 적용

 

Filtering

가끔 테스트를 하다보면 
특정 테스트만 실행하고 싶은 경우
가 있습니다. 특정 feature에 대해서만 테스트를 하고 싶다거나, 시간이 오래걸리는 통합 테스트는 제외시키고 테스트하고 싶다거나 말이죠. 이런 경우에 필터링해서 실행시킬 수 있습니다. 이를 위해서는 gradle 수정이 필요합니다.

 

위의 task 안에 inclueTag와 excludeTag 값을 통해 설정할 수 있습니다.

예시같이 설정한 경우, unit Tag 가 들어가면서 bar Tag 가 들어가지 않은 경우의 테스트를 수행하게 됩니다.

하지만 위와 같이 적용 시 gradle 설정에만 의존하여 테스트를 구성해야함

*// build.gradle*

*// `gradle test`: integration tag가 붙은 테스트는 제외*

tasks.named('test') {
    useJUnitPlatform {
        excludeTags 'integration'
    }
}

*// `gradle integrationTest`: integration tag가 붙은 테스트만 수행*

task integrationTest(type: Test) {
    useJUnitPlatform {
        includeTags 'integration'
    }
}

 

이를 탈피하기 위해 위와 같이 적용 가능

위의 설정을 풀어보자면

  • integration tag가 붙지 않은 테스트 실행: gradle test
  • integration tag가 붙은 테스트 실행: gradle integrationTest

사용하면서 느낀 점은 꼭 필요할때 써야하는데 불필요하게 붙는 경우가 많은 것 같다(테스트 코드를 제외시킬거라면 굳이 작성할 필요가 있을까..)

나의 경우에는 필요하지 않다 판단되면 disabled처리를 이용하는 편이다.

728x90
728x90

async 처리를 할때 로그인된 정보를 가져 올 수 없는 문제를 부딪쳤다.

 

@async 처리가 아닌 경우에는 aspectj 에서 로그인 정보를 정상적으로 가져오지만 async 처리 시에는 해당 정보를 호출시 NPE 에러가 떨어졌다.

 

해당 문제를 해결하기 위해 구글링을 하던중에 아래와 같은 해결 방법을 보게 되었다.

아래는 stackoverflow 

 

https://stackoverflow.com/questions/5246428/spring-security-and-async-authenticated-users-mixed-up

 

Spring Security and @Async (Authenticated Users mixed up)

I asynchronously invoke a method with Spring, using @Async. This method invokes another method annotated with @PreAuthorize, the Spring Security Annotation. To make the authorization work I have to...

stackoverflow.com

 

2가지 방법을 확인하였는데 나는 아래의 방법을 참조하여 해결하였다.

 

첫 번째 해결방법

public void execute(final Runnable r) {
    final Authentication a = SecurityContextHolder.getContext().getAuthentication();

    super.execute(new Runnable() {
        public void run() {
            try {
                SecurityContext ctx = SecurityContextHolder.createEmptyContext();
                ctx.setAuthentication(a);
                SecurityContextHolder.setContext(ctx);
                r.run();
            } finally {
                SecurityContextHolder.clearContext();
            }
        }
    });
}

 

위와 같이 excute 실행 전 authentication을 변수에 담아 두었다가 실행시 재 설정해주는 방법이다 .

 

 

실제 적용 코드

 

두번째 방법

config 설정 시 아래와 같이 설정하는 방법이 있다.

@Bean("threadPoolTaskExecutor")
public TaskExecutor getAsyncExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(20);
    executor.setMaxPoolSize(1000);
    executor.setWaitForTasksToCompleteOnShutdown(true);
    executor.setThreadNamePrefix("Async-");
    executor.initialize(); // this is important, otherwise an error is thrown
    return new DelegatingSecurityContextAsyncTaskExecutor(executor);
}

 

다음에 같은 문제가 발생한다면 config 로 공통적으로 해결이 가능하게 수정하면 좋을것 같다는 생각이 작성중에 들어 전체 리소스 리팩토링을 진행해야 할듯 하다.

728x90

'코드 > dev' 카테고리의 다른 글

java dateTime 타임존  (2) 2023.11.22
Junit test filtering  (2) 2023.11.17
저장소에 올라간 브랜치 되돌리기  (2) 2023.11.15
spring AOP & AspectJ  (1) 2023.11.15
mariaDB Schedule  (3) 2023.11.14
728x90

간혹 작업을 하다보면 하나의 리소스에 여러 브랜치를 만들어 작업을 하게 되는 경우가 있다.

A 브랜치를 올려서 배포를 해야하는데 모르고 B 브랜치 를 리베이스하여 올리게되는 큰 실수를 하게되었다…(작업은 역시 순차적으로 하나씩 처리하고 배포는 신중히..)

일단 문제를 해결하여야 하니
현재 재직중인 회사에서는 git tag 를 생성하여 배포를 하고 있어서 배포를 이전 배포 버전으로 재배포를 진행 후

1.이전 태그로 리셋
git reset --hard {tagName}
- 해당 태크 상태로 돌아가기

2.저장소 이전 태크 버전으로 변경
git push origin master- 해당 브랜치 저장소 재 push


이전 태크로 push를 하게 되면 아래와 같은 error를 마주하게된다.

error: failed to push some refs to …
로컬 저장소의 커밋 히스토리가 원격 저장소의 커밋 히스토리보다 뒤쳐져 있는데 푸시를 하였으므로 발생하는 에러이다.


이떄 당황하지 않고 아래와 같은 옵션을 이용하면 해결된다.

git push -f origin master- f는 force의 약자

 

 

 

위와 같은 방법으로 해결 이후 짧게 회고를 해보자면 항상 조심 또 조심해야 겠다는 생각이들고

뭔가 잘못되었을 때도 항상 침착함을 유지하고 빠르게 대처하는게 중요하다는걸 새삼 느낀다..

728x90

'코드 > dev' 카테고리의 다른 글

Junit test filtering  (2) 2023.11.17
비동기처리 시 Spring security 문제  (0) 2023.11.16
spring AOP & AspectJ  (1) 2023.11.15
mariaDB Schedule  (3) 2023.11.14
RestTemplate Get RequestBody 전송  (0) 2023.11.14
728x90

회사에서 데이터가 update가 이루어 질 시 이력 로그를 쌓아달라는 요청을 받아 어떤 방법으로 작업을 진행할까 하다가 
AOP와 ASpectJ 복습 겸 정리를 진행하게되었다.

 

  • AOP 란?
점 지향 프로그래밍(Aspect Oriented Progamming) 기법은 객체지향을 보완하는 수단으로, 흩어진 관점(Aspect)를 모듈화 하여 비즈니스 로직을 헤치지 않고 재사용하는 프로그래밍 기법이다.

 

 

 

스프링에서는 AOP를 쉽게 사용 할 수 있도록 어노테이션을 지원한다.

아래는 참고 코드와 컨테이너에서 어떻게 동작하는지를 보여주는 참고 이미지

 

 

 

  • AOP 용어
Aspect - 애플리케이션 내 여러 군데에 흩어져있는 코드/기능이며, 실제 비즈니스 로직과는 다릅니다.(예를 들면, 트랜잭션관리). 각 Aspect는 고유한 Cross-Cutting 기능에 초점을 맞추고 있습니다. 쉽게 말하면, 여러 객체에 공통적으로 적용되는 관심 사항을 Aspect라고 합니다.

쉽게 말하면, 여러 객체에 공통적으로 적영되는 관심 사항을 Aspect라고 합니다.

Joinpoint - 프로그램이 실행 중일 때 발생하는 메서드 실행, 생성자 호출, 필드 값 변경과 같은 특수한 지점을 의미

Advice - 특정 Joinpoint의 Aspect에 의한 동작을 의미합니다. 대상 객체의 Joinpoint에 Weaving되어 동작할 수 있는 코드를 의미합니다.

Pointcut - Joinpoint의 정규표현식, Joinpoint가 Pointcut에 일치할 때마다 해당Pointcut에 관련된 Advice가 실행됩니다.

Weaving - Aspect를 대상 객체에 연결시키 관점지향 객체로 만드는 과저을 의미합니다. Advice를 비즈니스 로직 코드에 삽입하는것을 의미합니다.

 

 

  • AspectJ란?
AspectJ 는 자바에서 완벽한 솔루션 제공을 목표로하는 기술

[ .aj 파일]을 이용한 assertj 컴파일러를 추가로 사용하여 컴파일 시점이나 JVM 클래스 로드시점에 조작한다.

런타임 시점에는 영향끼치지 않는다.

. 즉 컴파일이 완료된 이후에는 앱 성능에 영향이 없다.

밑에서 몸으로 느끼겠지만, Spring AOP에 비해 사용방법이 다양하고 내부 구조가 굉장히 복잡하다.

 

 

 

  • AspectJ와 Spring Aop 비교하기
1.기능과 목표가 다르다
Spring AOP는 프로그래머가 직면하는 일반적인 문제 해결을 위해 Spring IoC에서 제공하는 간편한 AOP 기능이다. 어디에나 쓸 수 있는 완벽한 AOP 솔루션이 아니라, Spring 컨테이너가 관리하는 Bean 에만 사용하려고 만들었고, 실제로 여기에만 AOP를 적용 할 수 있다.

AspectJ는 자바코드에서 동작하는 모든 객체에 대한 완벽한 AOP 솔루션 제공을 목표로 하는 기술이다. 성능이 뛰어나고 기능이 매우 강력하지만 그만큼 Spring AOP에 비해 사용방법이나 내부 구조가 훨씬 더 복잡하다.

2. Weaving 방법이 다르다.
Weaving은 공통관심사항(Aspect)의 동작코드(Advice)를 대상 객체(Target)에 연결시켜 관점지향을 구현한 객체로 만드는 과정이다.

좀 더 쉽게 말하면 AOP를 구현하기 위한 바이트코드 조작 방법을 의미한다고 생각하면 된다.

소스코드로 위빙을 구현(Source-code Weaving)하는게 가장 좋긴 하겠지만, 현재까지 자바언어가 제공하는 기능으로 완벽한 AOP를 구현하기 어렵다.

728x90

'코드 > dev' 카테고리의 다른 글

Junit test filtering  (2) 2023.11.17
비동기처리 시 Spring security 문제  (0) 2023.11.16
저장소에 올라간 브랜치 되돌리기  (2) 2023.11.15
mariaDB Schedule  (3) 2023.11.14
RestTemplate Get RequestBody 전송  (0) 2023.11.14

+ Recent posts