[Kotlin] data class

Kotlin|2019. 9. 9. 18:10

자바에서는 모델 혹은 DTO 혹은 Entity 클래스들을 만들때 

툴에 getter setter 을 자동으로 만들어주는 기능이나 롬복을 활용하여

해당 노가다를 줄이곤 했습니다.

 

코틀린에서는 data class가 존재하여 해당 부분에 코드를 간편히 생성할수 있도록 제공하고 있었습니다.

 

일단 data 클래스에서 제공하는 것은 

 

1. 모든 필드 기반 hashCode & equals 자동 구현

2. 모든 필드 기반 toString 자동구현

3. getter 대신 compoentN() // N은 필드순, 1 부터

4. copy(필드들), (args를 해당 객체를 받지 않고 필드들을 받아서 거의 생성자느낌에 구현이..)

 

들을 지원합니다.

 

Emp 클래스에 empno와 ename 이 있다고 했을때

자바로 Emp 클래스를 만들면

public class Emp {
	private Integer empno;
	private String ename;
	public Integer getEmpno() {
		return empno;
	}
	public void setEmpno(Integer empno) {
		this.empno = empno;
	}
	public String getEname() {
		return ename;
	}
	public void setEname(String ename) {
		this.ename = ename;
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((empno == null) ? 0 : empno.hashCode());
		result = prime * result + ((ename == null) ? 0 : ename.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Emp other = (Emp) obj;
		if (empno == null) {
			if (other.empno != null)
				return false;
		} else if (!empno.equals(other.empno))
			return false;
		if (ename == null) {
			if (other.ename != null)
				return false;
		} else if (!ename.equals(other.ename))
			return false;
		return true;
	}
	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("Emp [empno=").append(empno).append(", ename=").append(ename).append("]");
		return builder.toString();
	}

}

이렇게 장황한 코드가

 

코틀린으로는

data class Emp(
	var empno: Int?,
	var ename: String
) {
	constructor() : this(null,"")
}

 

이렇게 간단한 코드가 됩니다.

 

개발시 모델 변경이 자주 발생한다면 더더욱 큰 차이라고 볼수 있고

 

"나는 모델 변경이 거의 없는데?" 라고 하더라도

이슈로 모델코드를 자바코드를 봤을때 절대적으로 라인 코드가 길기 때문에

혹시 잘못 구현한 hashCode()나 null처리 등 체크하는것만으로도 낭비 시간들이 발생할수 있을것으로 생각됩니다.

(물론 자바를 사용하더라도 롬복을 쓰면 차이가 없지만요^^;;)

 

댓글()

[Spring][Kotlin] 필드에 @Autowired 어떻게 사용하나?

Kotlin|2019. 9. 6. 19:02

아직 익숙하지 않지만, 코틀린을 조금씩 학습중에 @Autowired를 어떻게 써야하는지 난감한 상황이 생겼습니다.

 

자바에서는 일반적으로 

 

@Autowired
private EmpDao empDao;

형태로 간단히 사용할수 있지만

 

코틀린에서

 

@Autowired
var empDao: EmpDao;

'Property must be initialized or be abstract' 에러와 함께 동작하지 않았습니다.

 

그럴때는'lateinit' 을 사용하면 에러 없이 사용가능합니다.

@Autowire
lateinit var empDao : EmpDao;

 

참고 : https://kotlinlang.org/docs/reference/properties.html#late-initialized-properties

'Kotlin' 카테고리의 다른 글

split과 동시에 assign  (0) 2021.11.29
코틀린 upgrade 1.3.7 to 1.5.0  (0) 2021.05.28
[Kotlin] default argument, named argument  (0) 2019.09.18
[Kotlin] 코틀린에 primitive가 없다고? 느리지 않을까?  (1) 2019.09.10
[Kotlin] data class  (0) 2019.09.09

댓글()

[CompletableFuture][#3] 메소드 정리-1

JAVA|2019. 9. 1. 20:40

지난번에 static 메소드를 정리해보았고

이제 CompletableFuture(이하 cf)의 메소드에 대해 정리해보려고 합니다.

정리하려고 public 메소드를 뽑아보았더니...

굉장히 길었습니다..

그래서 조금 나누어 정리해야 할것 같아 메서드 네이밍을 쭉 살펴보니

크게 두가지로 나눠 보았습니다.

  • 실행 후 제어(thenRun, handle....)
    • sync
      • acceptEither
      • applyToEither
      • handle
      • runAfterBoth
      • runAfterEither
      • thenAccept
      • thenAcceptBoth
      • thenApply
      • thenCombine
      • thenCompose
      • thenRun
      • whenComplete
    • async
      • acceptEitherAsync
      • applyToEitherAsync
      • handleAsync
      • runAfterBothAsync
      • runAfterEitherAsync
      • thenAcceptAsync
      • thenAcceptBothAsync
      • thenApplyAsync
      • thenCombineAsync
      • thenComposeAsync
      • thenRunAsync
      • whenCompleteAsync
  • async 한 작업을 대기하거나 상태를 확인 및 기타등등(get, isDone, join ....)
    • cacel
    • complete
    • completeExceptionally
    • exceptionally
    • get()
    • get(time)
    • getNow
    • getNumberOfDependents
    • isCancelled
    • isCompletedExceptionally
    • isDone
    • join
    • obtrudeException(Throwable)
    • obtrudeValue(R)

먼저 "실행 후 제어(thenRun, handle....)" 메서드 를 살펴보겠습니다.

위에 정리한것처럼 Async 가 붙은것 붙지 않은것이 각각 존재 합니다.

아직 다 살펴보지 않아 정확하지는 않지만 async가 메소드명에 붙고 안붙는것에 따라 sync/async가 갈릴것으로 파악 됩니다.

하나씩 살펴보겠습니다.

acceptEither

applyToEither

handle

runAfterBoth

runAfterEither

thenAccept

thenAcceptBoth

thenApply

thenCombine

thenCompose

thenRun

whenComplete

Async

acceptEitherAsync
applyToEitherAsync
handleAsync
runAfterBothAsync
runAfterEitherAsync
thenAcceptAsync
thenAcceptBothAsync
thenApplyAsync
thenCombineAsync
thenComposeAsync
thenRunAsync
whenCompleteAsync

Util
cacel
complete
completeExceptionally
exceptionally
get()
get(time)
getNow
getNumberOfDependents
isCancelled
isCompletedExceptionally
isDone
join
obtrudeException(Throwable)
obtrudeValue(R)

'JAVA' 카테고리의 다른 글

java.util.function 인터페이스  (0) 2019.12.30
JEP 218: Generics over Primitive Types  (0) 2019.12.10
[Quartz] Trigger  (0) 2019.07.10
[CompletableFuture][#2] staticMethod  (0) 2019.07.09
[CompletableFuture][#1] 정리시작  (0) 2019.07.03

댓글()

[Spring] zuul 사용시 Eureka client로 분배가 안되는경우

JAVA/Spring|2019. 8. 16. 19:56

Toy 프로젝트에 zuul 을 적용해서 사용해보고있는데

여러 appSvr를 EurekaServer에 붙이고 zuul로 호출해봤으나 이상하게도

하나의 appSvr로 호출되는 현상이 발생했습니다.

 

이게 원래 그런가?(active-standby로..?) 라고 처음에는 생각해봤지만 그건 너무 아닌것 같아서

이런저런 시도를 하다 eureakServer에 /eureka/apps 로 등록된 app을 확인해보니

zuul(API-GATEWAY)이랑 appSvr(MEMBER-API 라는 샘플..)이 정상적으로 등록되어있지만

appSvr가 3개가 나타나야 하는데 하나만 나타나는것을 확인했습니다.

 

등록된 정보들을 살펴보다가 떠오른것이..

eureka.instanceId 설정을.. 안했...네요..

 

설정을 안하다보니, ip:applicationName:port 으로 instanceId가 다 지정되어

(port는 일부러 random으로 띄우기 위해 0으로 설정했었습니다.)

동일한 instanceId 로 등록을 시도하고 있었던것 이였습니다.

 

그래서 'eureka.instance.instance-id' 설정을 추가해주었고

설정값은 'hostname:applicationname:springinstanceId:random값'

으로 하여 중복이 발생하지 않고 기존처럼 인식할수 있도록 변경하였습니다.

 

eureka.instance.instance-id=${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance_id:${random.value}}

 

간단한 설정 실수였지만.. 역시 reference 를 잘 읽어야.. 하겠습니다.

 

요약

1. eureka.instance.instance-id 를설정하지 않거나 중복 된다면 제대로 동작 안할수 있다.

 

 

 

댓글()

[Spring] JDBC Template 어떻게 Thread-Safe 할까?

JAVA/Spring|2019. 8. 6. 18:27

Spring 스터디중 나온 질문 입니다.

 

DAO 클래스를 만들때 "JDBC Template"는 new 해서 사용하기도 하지만, "Thread-Safe 하기 때문에 빈으로 등록해서 사용할 수 있다"

 

Toy 프로젝트 때는 MyBatis를 쓰거나, JPA를 사용하기 때문에 JDBC Template를 사용할 일이 많지 않았지만,

대체 내부 구조가 어떻게 되어있길래 Thread-Safe한거지? 라는 의문이 들었습니다.

(JDBC에 Connection, Statement, ResultSet 은 Thread-Safe 하지 않기 때문에..)

 

예상 할 수 있는건

락(sync)를 잡아 처리 하나? 아니면 ThreadLocal로 처리하나?

정도로 예상해볼수 있는데 락잡아 처리한다면.. 쫌 아닐꺼라 생각되지만 코드를 살펴봤습니다.

JdbcTemplate의 query, update, execute 등 대부분의 메소드들은 살펴보면 메소드 내에서

DataSourceUtils.getConnection(ds) 를 통해 Connection을 얻어오고 있으며

메소드에서 생성된 ps나 rs 그리고 connection(물론 connection은 무조건 정리하지는 않습니다.) 정리 하고 있습니다.

//즉, JdbcTemplate 객체에 상태 변화 없이 메소드 내에서 모든 리소스가 정리 됨

 

JdbcTemplate 객체내에서 리소스(예를 들어 Connection)를 정리하지 않고 보존해야 하는경우도 있는데

(예를 들어 @Transaction)

그경우를 위해 DataSourceUtils.getConnection(ds) 코드를 따라가보면

TransactionSynchronizationManager.getResource(ds)를 통해 ConnectionHolder를 가져오는데

TransactionSynchronizationManager.getResource(ds)를 더 들어가보면

ThreadLocal<Map<Object,Object>>로 되어있는 resources를 가져와 ds를 키로 ConnectionHolder를 가져오는것을 볼수 있었습니다.

 

 

 

결론

1. JdbcTemplate 인스턴스는 상태를 갖지 않고 메소드 내에서 생성된 리소스(rs, ps, connection) 들을 정리하기 때문에 Thread-Safe하다

2. Transaction이 필요한경우 정리하면 안되는 Connection의 경우 JdbcTemplate이 상태를 가지지 않고TransactionSynchronizationManager에 ThreadLocal로 보관 하기 때문에 JdbcTemplate를 Thread-Safe하며,

Connection 객체 전달 및 전파 필요 없이 트랜잭션 제어를 하기 용이 하다.

 

 

댓글()

[Azure] SpringBoot, AppService로 배포

JAVA/Spring|2019. 8. 2. 18:51

개인 Toy 프로젝트를 라즈베리파이를 통해 개발하다 요즘 MS Azure를 활용하여 개발중입니다.

AWS를 쓰다 무료기간이 지난후 과금으로 인해 Cloud를 사용하지 않고 있다 살펴보니 좋더군요..

 

구글도 아마존도 MS 도 다 비슷하게 1년동안 무료로 제공하고 있으니 

꼭 Azure를 사용할 필요는 없습니다.

 

ms azure는 한달 22만원에 크레딧을 제공하고 있습니다

https://azure.microsoft.com/ko-kr/free/

처음에는 1년에 22만원을 제공하나? 해서 조금씩 써야겠다고 생각했지만.. 매달 지원해주고 있습니다.

 

'Virtual machines'로 우분투 서버를 에 수동으로 App을 배포해서 사용해도 되겠지만

'App Services' 서비스에 배포 하는 방법을 알아보았습니다.

 

이런저런 방법들을 시도해도 잘 되지 않아 괜히 고생했지만 결국 현재 사용하고 있는 방법을 담고 있는 링크는

https://docs.microsoft.com/ko-kr/java/azure/spring-framework/deploy-spring-boot-java-app-with-maven-plugin?view=azure-java-stable

 

를 참고하였습니다.

 

SpringBoot App을 개발후 'Azure App Service'에 배포하기 위해 필요한 내용은 사실

"Azure App Service용 Maven 플러그인 구성" 부터 보면 됩니다.

 

0. azure cli 설치 및 로그인(https://docs.microsoft.com/ko-kr/cli/azure/?view=azure-cli-latest)

0.1 배포시 az 인증이 필요하기 때문에 az login 커맨드를 통해 로그인

 

az cli 설치 하지 않고 배포하는방법은 추후 발견하게되면 첨부 하겠습니다..

 

1. pom.xml 에 azure 플러그인을 추가

<plugin>
 <groupId>com.microsoft.azure</groupId>
 <artifactId>azure-webapp-maven-plugin</artifactId>
 <version>1.6.0</version>
</plugin>

2. mvn azure-webapp:config 수행

2.1 배포할 환경 설정하게 됩니다.(OS, javaVersion 등)

2.2 위 설정 이후 pom.xml에 <configuration> 항목에 설정한 내용들이 추가 되는데, 여기서 <region>이 미국으로 설정되던데 한국으로 바꾸고 싶다면 <region>koreacentral</region> 으로 바꾸시면 됩니다.

2.3 pom.xml에 appName과 resourceGroup 모두 적힌 그대로 배포되기 때문에 필요하면 배포전 수정하시기 바랍니다.

 

3. port 설정을 위해 <appSettings>에 JAVA_OPTS ,-Dserver.port=80 설정

3.1 저는 추가로 profile 설정이 필요해서 SPRING_OPTS 로 설정을 시도해보았지만 안되어 JAVA_OPTS에 -Dserver.port=80 -Dspring.profiles.active=run 설정하여 정상적으로 동작했습니다.

 

 

4. 설정파일은 다 됬고 이제 배포

4.1 mvn clean package

4.2 mvn azure-webapp:deploy

4.3 4.2을 하다가 인증 에러 발생시 0.1 에 로그인 다시 진행

 

5. 배포 완료 

5.1 이제 포탈에서 적혀있는 url로 접속하여 정상적으로 접속 되는지 확인하면 됩니다.

 

Azure 에 'App Services'는 'Virtual machines' 과 달리 

Development Tools 이나 Scale out 과  같은 기능들도 지원되고 있습니다.

 

 

아직은 기본적으로 각 AppService만 띄워 사용중인데 추후 기회가 된다면

제공하고 있는 기능들을 활용 후 정리해두도록 하겠습니다.

 

댓글()

[Quartz] Trigger

JAVA|2019. 7. 10. 18:16

중간에 내용이 다 날아가버렸어요...ㅠㅠ


Quartz에서 사용하고 있는 Trigger에 대해 다룬 내용이었는데..

컴퓨터가 리붓하면서.. 다 날아갔...



어쩔 수 없이 짧게나마 글을 다시 작성합니다!



Quartz에 Trigger의 종류는

사실 많아보이지만 구현체는 총 4가지

  • SimpleTriggerImpl
  • DailyTimeIntervalTriggerImpl
  • CalendarIntervalTriggerImpl
  • CronTriggerImpl

각 항목들을 가지고, 어떠한 요소들을 가지고 Job을 Triggering 하는지 살펴보려고 합니다.

 

물론, Trigger는 직접 생성하지 않고 TriggerBuilder와 ScheduleBuilder를 통해 객체를 생성하고

옵션 값들을 세팅하지만, 결국에는 Trigger 클래스가 생성되기에 Builder는 건너뛰고 Trigger를 살펴봅니다.

 

Common

공통적으로

스케줄이 유효한 기간에 해당하는 startTime과 endTime은 존재합니다.

 

SimpleTriggerImpl

SimpleTriggerImpl은 이름답게 가장 간단한 Trigger로 repeatCnt와 repeatInterval을 통해

단순하고 주기적인 스케줄링을 지원합니다.

repeatCnt는 -1이면 무한, 0 < 이면 그 횟수만큼 호출합니다.

repeatInterval은 단위가 milliseconds 입니다.

 

DailyTimeIntervalTriggerImpl

DailyTimeIntervalTriggerImpl은 SimpleTriggerImpl 보다 조금 더 확장된 Trigger이며

네이밍답게 하루하루에 집중되어있습니다.

마찬가지로 repeatCnt, repeatInterval이 존재하지만, repeatIntervalUnit 값이 존재하여  millisecond 뿐 아니라 다양한 시간대를 지원합니다.

또한 하루하루 스케줄링에 집중된 만큼 하루에 어떤 시간대에 유효한지(오전 9~오후 6)도 지정할 수 있으며(startTimeOfDay, startTimeOfDay)

특정 요일에만 실행할 수 있는 기능이 있습니다(daysOfWeek).

 

CalendarIntervalTriggerImpl

CalendarIntervalTriggerImpl은 마찬가지로  repeatInterval, repeatIntervalUnit이 존재하며

다른 트리거와 다르게 repeatCnt가 없고, TimeZone을 지정할 수 있으며

preserveHourOfDayAcrossDaylightSavings, skipDayIfHourDoesNotExist 두 개의 boolean 값이 존재한다.

 

CalendarIntervalTriggerImpl은 조금 익숙하지 않은 트리거라 조금 더 살펴본 후 내용을 추가로 보강할 예정입니다.

 

 

CronTriggerImpl

CronTriggerImpl은 흔히 사용하는 트리거로 CronExpression을 사용하여

스케줄 조건을 지정할 수 있는 Trigger입니다.

표현식을 직접 지정하거나, Quartz 라이브러리에 포함되어있는 CronExpression의 클래스에 객체를 생성하여 설정할 수도 있습니다.

CronExpression 안에 TimeZone도 물론 있습니다.

 

 

[TODO] Trigger 코드를 살펴보던 중 misFire에 대한 MisfireInstruction에 대한 내용 및 코드가 상당히 많았습니다.

기존 스케줄러를 만들 때 Misfire에 대해서는 고려 안 한 부분들이 있었는데

해당 부분은 조금 더 고민 및 학습 후 여기에 내용 추가 혹은 신규 글을 작성하도록 하겠습니다.

 

감사합니다.

댓글()

[CompletableFuture][#2] staticMethod

JAVA|2019. 7. 9. 19:00

static 메서드를 어떤 동작들을 하는지 파악 및 정리해보았습니다.

 

일단 알아볼 CompletableFuture static메서드 종류는 

  1. allOf
  2. anyOf
  3. completedFuture
  4. runAsync
  5. supplyAsync

 

먼저 allOf(..)

allOf anyOf와 마찬가지로 여러 개의 CompletableFuture를 args로 받고 있습니다.

소스를 열어보면 설명이 친절하게 달려있습니다(물론 영어..).

필요한 부분 일부만 해석을 해보면..

allOf(..)는

  • CompletableFuture 객체(이제 cf 객체라 줄임)를 반환하며 반환한 cf 객체는 args로 주어진 cfs들이 모두 완료되면 completed 됩니다.
  • 그리고 args로 들어온 cfs 중에 예외가 발생한 경우 CompletaionException으로 감싸서(기존 에러는 cause로 담아) 마지막에 에러로 발생됩니다.//결국 에러를 cf의 응답으로 취급하여 모든 에러 혹은 결과를 기다림
  • 여러 개의 cf들을 다 기다릴 때 사용됩니다.
  • args가 없으면 바로 완료된 cf를 반환합니다.
  • [TODO] andTree 내부 구현을 보면 BiRelay 가 사용되고 있는데 다음에 살펴볼 예정입니다.

 

anyOf(..)는

  • 반환한 cf 객체는 args로 주어진 cfs들 중 어떤 것이라도 완료되면 completed 가 됩니다.
  • 그리고 args로 들어온 cfs 중에 예외가 발생한 경우 CompletaionException으로 감싸서(기존 에러는 cause로 담아) 바로 에러로 발생됩니다.//에러를 응답으로 취급, 응답이 왔기에 즉시 리턴
  • 여러 개 중 하나의 cf를 기다릴 때 사용됩니다..
  • args가 없으면 바로 완료되지 않은 cf를 반환
  • [TODO] 3개 중 2개를 기다려야 한다면 어떻게 해야 하지..?

completedFuture(value)는

  • arg value를 result 필드로 들고 있고 완료되어있는 cf 객체를 반환

runAsync(Runnable,@Optional Executor)는

  • async 하게 처리되고 있는 cf 객체를 반환하며(runnable이니 result는 null)
  • executor가 지정되어있지 않으면 ForkJoinPool을 통해 running 된다.
  • 내부 코드에서는 cf에 innerClass인 AsyncRun 사용

  • [TODO] java.util.concurrent.ForkJoinPool

 

supplyAsync(Runnable,@Optional Executor)는

 

  • async 하게 처리되고 있는 cf 객체를 반환하며(supplier를 받으니 result는 U )
  • executor가 지정되어있지 않으면 ForkJoinPool을 통해 running 됩니다.
  • 내부 코드에서는 cf에 innerClass인 AsyncSuppy 사용

 

이번에는 먼저 cf에 static 메서드만 알아보았고

다음에는 일반 메서드들 및 내부에서 많이 사용하고 있는 메서드들을 주로 파악할 예정입니다.

댓글()