SpringBoot App에 외부 libs 추가

JAVA/Spring|2023. 11. 19. 22:57

SpringBoot는 기본적으로 jar내에 BOOT-INF에 classes, libs를 클래스패스로 물고 올라간다.

build.gradle혹은 pom.xml에 설정하여 빌드 타이밍에 같이 묶긴하면 BOOT-INF에 포함되어 사용하는데 문제 없지만

별도 jar로 제공 받아 활용을 해야한다면.

추가적으로 외부의 Libs를 ClassPath를 설정하기 위해서는 PropertiesLauncher 를 사용하고

-Dloader.path 를 설정하여 외부 jar도 활용 가능하다.

(특정 Bean을 external.jar로 만들어 추가한다거나..)

 

ex)

java -cp bootApp.jar -Dloader.path=external-plain.jar org.springframework.boot.loader.PropertiesLauncher

java -cp bootApp.jar -Dloader.path=plugins/ org.springframework.boot.loader.PropertiesLauncher

https://www.masterspringboot.com/configuration/web-server/how-to-use-an-external-jar-in-a-spring-boot-application/

'JAVA > Spring' 카테고리의 다른 글

[Spring] SessionStatus는 어떻게 동작할까?  (5) 2020.09.08
[JPA] LockType  (0) 2020.07.23
[Spring] LifeCycle, SmartLifeCycle  (0) 2020.06.23
[MSA] sidecar 패턴  (0) 2020.01.13
[SpringConfig] Properties 암호화  (0) 2019.12.24

댓글()

[Spring] SessionStatus는 어떻게 동작할까?

JAVA/Spring|2020. 9. 8. 17:02

Spring MVC 에서 SessionStatus 라는것이 존재합니다.

(현재는 대부분의 서비스회사들이 Session을 사용하지 않기 때문에 사용하지 않는 회사들은 무의미 할수 있겠네요)

 

SessionStatus는 @SessionAttributes를 활용해 Session에 남긴 데이터를 정리하는데 활용을 하는 인터페이스 입니다.

(Controller에 args로 선언해두면 injection이 되며 정리는 setComplete() 를 통해 정리 flag를 세팅합니다.)

 

SessionStatus 에 setComplete()를 호출하게 되면 내부적으로 complete boolean을 세팅하게 되고

RequestMappingHandlerAdapter에서 modelFactory의 updateModel() 내부에서 대상 attribute들을 정리하게 됩니다.

 

여기서 @SessionAttributes이 등장하는데

 

@SessionAttributes는 names를 args로 받게 되고

지정된 names들에 대해서 model에 접근하면 기존 model 저장소가 아닌 Session 영역까지 확장되도록 도움을 줍니다.

 

 

model.addAttribute("dutch", "hello");

 

일반적으로 위 코드 처럼 "dutch" 라는 키로 model에 세팅하면

응답 이후 값이 삭제 됩니다.

 

하지만 컨트롤러 클래스 상단에  @SessionAttribues 를 세팅 후 사용한다면 동작이 변경되게 됩니다.

@RequestMapping("dutch")
@Controller
@SessionAttributes("dutch")
public class DutchController

@SessionAttributes선언 후 model.addAttribute 를 호출한다면 해당 key,value가 Session에 저장 되고,

다음 요청이 동일 세션으로 왔을때 session의 Key를 "dutch"로 조회하면 addAttribute값이 존재하는것을 볼 수 있습니다. 그리고 model을 통해 "dutch"를 조회했을때도 값이 존재하는것을 확인 할 수 있습니다.

 

주의해야할 사항은 해당 컨트롤러가 아닌, 다른 컨트롤러에서 모델에서 "dutch"으로 값을 얻으려 시도하면

값이 들어 있지 않습니다.

위의 컨트롤러의 경우에는 model에 "dutch" 에 해당하는 값을 줘! 라고 하면 @SessionAttributes가 설정되어있는 Key는 Session에서 값을 찾지만

@SessionAttributes("dutch") 가 달려있지 않은 컨트롤러에서 model에 ""dutch" 에 해당하는 값을 줘!" 라고 한다면

Session에서 찾는게 아니라 정말 model에서 찾기 때문에 값이 존재 하지 않습니다.

 

 

 

'JAVA > Spring' 카테고리의 다른 글

SpringBoot App에 외부 libs 추가  (0) 2023.11.19
[JPA] LockType  (0) 2020.07.23
[Spring] LifeCycle, SmartLifeCycle  (0) 2020.06.23
[MSA] sidecar 패턴  (0) 2020.01.13
[SpringConfig] Properties 암호화  (0) 2019.12.24

댓글()

[JPA] LockType

JAVA/Spring|2020. 7. 23. 19:16

주로 업무상 디비 락이 필요한경우 Select for update를 주로 활용했는데
optimistic lock을 JPA에서 편리하게 사용할수 있게 지원하고 있어
테스트를 하며 정리해봤습니다.
(@Version이 있고 없고, 변경사항이 있을때 어떤 쿼리가 발생하는지 등)

작성한 github 위치 : https://github.com/Meteorkor/JPA_Study/edit/master/docs/LockType.md

테스트 코드는 추후 정리해서 업로드 예정입니다.

LockModeType

  • OPTIMISTIC

    • 트랜잭션 중 변경사항이 있을때
      • SELECT : 이때 버전을 같이 가져옴(해당 필드에 @Version, org.springframework.data.annotation.Version 가 아니라 javax.persistence.Version)
      • UPDATE : 이때 앞에서 Select한 version을 where에, set절에는 version=version+1 으로 version 업데이트
        • UPDATE 된 값이 없으면 중간에 버전이 변경된것으로 파악하여 에러 발생
    • 트랜잭션 중 변경사항이 없을때
      • SELECT : 이때 버전을 같이 가져옴(해당 필드에 @Version, org.springframework.data.annotation.Version 가 아니라 javax.persistence.Version)
      • SELECT : 이때 앞에서 Select한 version을 where에, 조회된 결과가 없으면 에러 발생
    • 수정을 하게 되면 version은 한개씩 올라감, 수정을 하지 않으면 version은 올라가지 않음
  • OPTIMISTIC_FORCE_INCREMENT

    • 트랜잭션 중 변경사항이 있을때
      • SELECT : 이때 버전을 같이 가져옴(해당 필드에 @Version, org.springframework.data.annotation.Version 가 아니라 javax.persistence.Version)
      • UPDATE : 이때 앞에서 Select한 version을 where에, set절에는 version=version+1 으로 version 업데이트
        • UPDATE 된 값이 없으면 중간에 버전이 변경된것으로 파악하여 에러 발생
      • UPDATE : Version을 한번 더 업데이트
    • 트랜잭션 중 변경사항이 없을때
      • SELECT : 이때 버전을 같이 가져옴(해당 필드에 @Version, org.springframework.data.annotation.Version 가 아니라 javax.persistence.Version)
      • UPDATE : Version을 업데이트
    • 수정을 하게 되면 version은 두개씩 올라감
    • 수정을 하지 않으면 version은 한개씩 올라감
  • READ(OPTIMISETIC과 동작 같음)

  • WRITE(OPTIMISTIC_FORCE_INCREMENT 과 동작 같음)

  • PESSIMISTIC_READ

    • @Version이 없는 경우
      • 트랜잭션 중 변경사항이 없을때
        • SELECT FOR UPDATE
      • 트랜잭션 중 변경사항이 있을때
        • SELECT FOR UPDATE - UPDATE
    • @Version이 있는 경우
      • 트랜잭션 중 변경사항이 없을때
        • SELECT FOR UPDATE
      • 트랜잭션 중 변경사항이 있을때
        • SELECT FOR UPDATE - UPDATE(version도 함께 올라감)
  • PESSIMISTIC_WRITE

    • @Version이 없는 경우
      • 트랜잭션 중 변경사항이 없을때
        • SELECT FOR UPDATE
      • 트랜잭션 중 변경사항이 있을때
        • SELECT FOR UPDATE - UPDATE
    • @Version이 있는 경우
      • 트랜잭션 중 변경사항이 없을때
        • SELECT FOR UPDATE
      • 트랜잭션 중 변경사항이 있을때
        • SELECT FOR UPDATE - UPDATE(version도 함께 올라감)
  • PESSIMISTIC_FORCE_INCREMENT

    • @Version이 없는 경우
      • 에러 발생
    • @Version이 있는 경우
      • 트랜잭션 중 변경사항이 없을때
        • SELECT FOR UPDATE - update version
      • 트랜잭션 중 변경사항이 있을때
        • SELECT FOR UPDATE - update version - updateUPDATE(version도 함께 올라감)
  • NONE

'JAVA > Spring' 카테고리의 다른 글

SpringBoot App에 외부 libs 추가  (0) 2023.11.19
[Spring] SessionStatus는 어떻게 동작할까?  (5) 2020.09.08
[Spring] LifeCycle, SmartLifeCycle  (0) 2020.06.23
[MSA] sidecar 패턴  (0) 2020.01.13
[SpringConfig] Properties 암호화  (0) 2019.12.24

댓글()

[Spring] LifeCycle, SmartLifeCycle

JAVA/Spring|2020. 6. 23. 19:02

kafkaMessageListener를 살펴보다가 

SmartLifecycle을 통해 org.springframework.kafka.listener.ConcurrentMessageListenerContainer 를 start 시키는것을 보고

 

SmartLifecycle과 LifeCycle에 대해 조금 살펴보았습니다.

추후 이와같이 서버 기동시에 세팅하고 종료 시키는 Bean이 필요하면 써먹으면 어떨까 합니다.

기존에는 초기화 Bean 을 만들고 @PostConstruct를 달아 초기화 로직을 돌리고 종료는 알아서 하곤 했습니다.

 

org.springframework.context.SmartLifeCycle은 Lifecycle, Phased 인터페이스를 구현한 인터페이스 입니다.

SmarLifeCycle을 살펴보기 이전에 LifeCycle을 살펴보고 SmarLifeCycle 을 살펴보겠습니다.

 

LifeCycle

LifeCycle은 라이프 사이클을 컨트롤 하기위해 start(), stop(), isRunning() 메소드로 구성되어 있으며

주석을 살펴보니 LifeCycle 인터페이스는 자동실행은 담당하지 않고 자동실행을 하고 싶으면"SmartLifecycle"을 활용하라고 되어있습니다.

 

Bean이 LifeCycle 인터페이스를 구현한다면 ApplicationContext에서 Start와 Stop 시그널을 준다고 되어있고

JMX를 통해서도 제어 가능하다고 되어있습니다

 

그리고 주요한 부분중 하나는 Scope가 "싱글톤" 일때만 동작한다는 것 입니다.

(테스트 해보니 "프로토타입"의 경우 동작하지 않는것을 확인 했습니다.)

(서버 다운시 ShutDown Hook에서 동작하다 보니 프로토타입은 적합하지 않나봅니다)

(동작하려면 서버 종료때까지 Bean이 살아있어야 한다는 말이기 때문에..)

 

SmarLifeCycle

SmarLifeCycle은 위에 적은대로 Lifecycle, Phased 를 구현한 인터페이스이지만 LifeCycle과 동작이 조금 다릅니다.

종료시점에 isRunning을 체크하여 stop을 호출해준다는 부분은 같지만

앞에 설명대로 SmartLifeCycle은 자동 실행으로 기동시점에 start() 메소드를 호출해줍니다.

DefaultLifecycleProcessor:140에 startBeans를 보면, 두 가지 Bean 모두 lifecycleBean 맵에 존재 하지만 체크로직으로 SmarLifecycle Bean만 phases에 들어가는 것을 볼수 있고 하단에 start()를 호출해주는 부분을 볼수 있습니다.

 

그리고 종료(stop)하는 부분도 LifeCycle살짝 다르긴한데

DefaultLifecycleProcessor:221에 doStop을 보면, SmarLifecycle은 Callback을 넘겨받는 stop이 불리며

Lifecycle은 단순 stop만 호출하고 끝나는 것을 볼수 있습니다.

 

 

서버 다운시 돌고있는것을 정리만 해주기 원한다면 Lifecycle을 

서버 부팅시 start, 종료시 stop 모두 서버와 Lifecycle을 함께 간다면 SmartLifecycle Bean을 고려해보는것도 좋을것 같습니다.

 

'JAVA > Spring' 카테고리의 다른 글

[Spring] SessionStatus는 어떻게 동작할까?  (5) 2020.09.08
[JPA] LockType  (0) 2020.07.23
[MSA] sidecar 패턴  (0) 2020.01.13
[SpringConfig] Properties 암호화  (0) 2019.12.24
spring boot log level 변경(actuator)  (0) 2019.12.19

댓글()

[MSA] sidecar 패턴

JAVA/Spring|2020. 1. 13. 19:41

개인적으로 개발할때는 Spring만 사용해왔기 때문에 Sprin Cloud는 살펴보곤 했지만

폴리글랏은 고려하지 않았기 때문에 다른것들은 살피지 않았습니다.

 

하지만, 최근에 회사에서 istio 라는 서비스 매쉬 패턴을 구현한 시스템? 을 살펴볼일이 있었습니다.

 

해당 시스템은 폴리글랏을 지원하기 위하여 각각의 언어별로 라이브러리를 제공하는 형식이 아닌

SideCar 패턴(Cloud 기능을 갖은 프로세스이며, Proxy 역할을 하는 프로세스)을 통해 Cloud 기능들을 언어 상관없이

지원하는 방향으로 설계 된것을 살펴보며 

자바에 거의 한정된 netflix oss가 아닌 istio가 인기있을만하다는 생각을 하며

 

그렇다면 "netflix oss에는 sidecar 패턴 구현체가 없나? 아니면 고려한 부분이 없나?"라는 생각으로 검색을 해보았습니다.

(필요시 없으면 그냥 SpirngBoot App 하나로 Proxy 형식으로 하나 만들면 되겠다는 생각도 하기도 했습니다)

 

그런데... 역시 있군요..

https://cloud.spring.io/spring-cloud-netflix/multi/multi__polyglot_support_with_sidecar.html

 

 

9. Polyglot support with Sidecar

9. Polyglot support with Sidecar Do you have non-JVM languages with which you want to take advantage of Eureka, Ribbon, and Config Server? The Spring Cloud Netflix Sidecar was inspired by Netflix Prana. It includes an HTTP API to get all of the instances (

cloud.spring.io

신기술 마냥 이제서야 접했지만 역시 세상은 넓다는걸 경험했습니다..;;

 

추후 istio관련 이야기가 지속된다면 각각 학습한 내용? 정리할 내용들을 시간이 되면 포스팅할것 같습니다

 

'JAVA > Spring' 카테고리의 다른 글

[JPA] LockType  (0) 2020.07.23
[Spring] LifeCycle, SmartLifeCycle  (0) 2020.06.23
[SpringConfig] Properties 암호화  (0) 2019.12.24
spring boot log level 변경(actuator)  (0) 2019.12.19
reactor Schedulers  (0) 2019.12.16

댓글()

[SpringConfig] Properties 암호화

JAVA/Spring|2019. 12. 24. 19:15

현재 토이 프로젝트에 Spring Cloud Config Server를 덕분에 설정을 편하게 사용하고 있습니다.

(config repo는 github를 사용하고 있는데 잘 되네요, 내역 관리도 되고 github 들어가서 수정하기도 편하니)

 

그런데 설정중에 암호에 대한 설정들이 있습니다.

 

현재는 혼자서 개발중이기 때문에 문제 없지만 공용 repo에 암호를 그대로 노출한다는게 조금 찝찝함은 있습니다.

 

그래서 미뤄놓았던것중 하나인 설정 암호화를 적용하려고 합니다.

 

설정 암호화는

https://github.com/ulisesbocchio/jasypt-spring-boot

 

ulisesbocchio/jasypt-spring-boot

Jasypt integration for Spring boot. Contribute to ulisesbocchio/jasypt-spring-boot development by creating an account on GitHub.

github.com

에 올라와있는 jasypt-spring-boot를 사용하여 처리하려고 합니다.

 

간단히 pom.xml에 해당 의존성을 추가하고

(최신버전이 3.0.0이네요)

<dependency>
      <groupId>com.github.ulisesbocchio</groupId>
      <artifactId>jasypt-spring-boot-starter</artifactId>
      <version>3.0.0</version>
    </dependency>

 

properties에 암호화 키를

jasypt.encryptor.password= xxx 로 설정합니다.

 

그후에 StringEncryptor로 

 

    @Autowired
    StringEncryptor encryptor;

    @Test
    public void test(){

        String defaultStr = "aa131";

        String encrytStr = encryptor.encrypt(defaultStr);

        System.out.println("encrytStr : " + encrytStr);

        String decrytStr = encryptor.decrypt(encrytStr);
        System.out.println("decrytStr : " + decrytStr);

//        System.out.println("encrypt : " + encryptor.encrypt("a"));

    }

와 같이 암호화된 패스워드를 구합니다.

(org.jasypt.exceptions.EncryptionOperationNotPossibleException 와 같은 에러가 발생할 수 있는데, 검색해보시면 oracle에서 JCE 파일을 받아서 해결하는 방법을 찾을수 있습니다.)

암호화된 패스워드를 ENC() 로 감싸서 설정합니다.

 

spring.data.mongodb.password=ENC(xxxxxx)
jasypt.encryptor.password= xxx

설정을 변경후 기존 서버를 부팅시켜보면 정상적으로 동작하는것을 볼 수 있는데

 

같은 properties 파일에 암호키랑 암호화된 정보를 둘다 같고 있는건 조금 아니다 싶습니다.

 

그래서 어떻게 분리 시킬까 하다

저는 bootstrap.yml 에 

jasypt.encryptor.password 설정을 분리하고

properties에는 암호화된 값(ENC) 만 남겨 분리 했습니다.

jasypt:
  encryptor:
    password: xxxxxx

 

 

 

'JAVA > Spring' 카테고리의 다른 글

[Spring] LifeCycle, SmartLifeCycle  (0) 2020.06.23
[MSA] sidecar 패턴  (0) 2020.01.13
spring boot log level 변경(actuator)  (0) 2019.12.19
reactor Schedulers  (0) 2019.12.16
스프링 부트 2.2 릴리즈노트  (0) 2019.11.01

댓글()

spring boot log level 변경(actuator)

JAVA/Spring|2019. 12. 19. 19:50

로그레벨 동적 반영을 위하여

Controller를 하나 만들어서 처리할까 하다 이미 구현된 기능이 있을지 해서 검색해보니

이기 해당 기능이 actuator를 이용하여 처리가 가능하도록 되어있었습니다.

 

먼저 actuator를 사용하기 위해 pom.xml 에 추가합니다.(메이븐 기준으로)

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

 

설정 없이는 /actuator 로 확인할수 있는것들이 없지만 'management.endpoints.web.exposure.include' 에 항목들을 추가하여 추가적인 기능들을 사용할 수 있습니다.

management.endpoints.web.exposure.include=loggers

#management.endpoints.web.exposure.include=httptrace,loggers,health,info,metrics

 

logger 설정 및 확인을 위해 필요한 내용은 loggers입니다.

 

위와같이 설정 후 기동하게되면

'/actuator/loggers' 를 통해 모든 로거들의 로그레벨들을 확인할 수 있습니다.

 

 

'/actuator/loggers/로거명' 을 GET으로 요청하면 해당 로거만 나타나게 됩니다.

 

이제 목표인 로그레벨 동적 변경을 위해서는

'/actuator/loggers/로거명' 에 POST로 설정할 값을 보내주면 됩니다.

{"configuredLevel":null,"effectiveLevel":"INFO"} 를

{"configuredLevel":"ERROR","effectiveLevel":"ERROR"} 로 변경하고자 하면

 

헤더는 컨텐츠 타입을 application/json에 body에 {"configuredLevel":"ERROR","effectiveLevel":"ERROR"} 을 넣어 요청하도록 하면 됩니다.

 

 

 

'JAVA > Spring' 카테고리의 다른 글

[MSA] sidecar 패턴  (0) 2020.01.13
[SpringConfig] Properties 암호화  (0) 2019.12.24
reactor Schedulers  (0) 2019.12.16
스프링 부트 2.2 릴리즈노트  (0) 2019.11.01
[Spring] zuul 사용시 Eureka client로 분배가 안되는경우  (0) 2019.08.16

댓글()

reactor Schedulers

JAVA/Spring|2019. 12. 16. 20:47

Mono 혹은 Flux를 다룰때 map 혹은 subscribe 동작들을
subscribeOn()이나 publishOn()을 통해 다른 스레드에서 실행될 수 있도록 위임할수 있는데
인자는 Scheduler를 받습니다.


Spring WebFlux에서 Controller 스레드에서는 blocking 작업을 할수 없도록 되어있기에
필요한 경우에 subscribeOn() 를 사용하여 blocking 작업을 다른 스레드에서 사용할 수 있는데
Scheduler 종류마다 blocking 작업이 가능한 Scheduler가 있고 아닌 Scheduler 가 있습니다.
(non-blocking 스케줄은 블럭킹 작업이 불가능합니다.)





새로 신규로 생성하여 넘길수 있겠지만 Schedulers가 기본적으로 몇가지를 지원합니다.

  • parrallel
    • optimized for fast non-blocking executions
    • 속도 최적, non-blocking
  • single
    • optimized for low-latency one-off executions
    • 스레드 하나를 공유함, non-blocking
  • elastic
    • optimized for longer executions, alternative for blocking tasks where the number of active tasks can grow indefinitely
    • 긴작업에 최적, non-blocking 아님, blocking 작업 가능 스레드, 필요시 무한히 늘어남
  • boundedElastic
    • optimized for longer executions, alternative for blocking tasks where the number of active tasks is capped
    • 긴작업에 최적, non-blocking 아님, blocking 작업 가능 스레드, 정해진 사이즈
  • immediate
    • to run a task on the caller Thread
    • 콜러 스레드에서 실행
  • fromExecutorService
    • 기존 java.util.concurrent.Executors 를 활용

댓글()