'Spring'에 해당되는 글 49건

  1. 2022.04.07 [Springboot+Ajax] 데이터 통신
  2. 2022.03.23 [Docker] Spring Boot App 도커 적용
  3. 2021.12.07 [Elasticsearch] LLRC + Springboot 성능 튜닝 팁
  4. 2021.11.30 [Spring] bean name conflict resolve.
  5. 2021.11.30 [Spring] @Autowired vs @RequiredArgsConstructor
  6. 2021.10.20 [Spring] Intellij Community + Springboot Profile 활용
  7. 2021.09.16 [SpringBoot] 깡통 프로젝트 생성 후 실행 시 에러 (Error creating bean with name 'dataSource' defined in class path resource)
  8. 2021.03.03 [Spring] Event Pub/Sub 기능 예제
  9. 2021.02.22 [Spring] 멀티모듈 프로젝트 jar SKIPPED
  10. 2021.01.28 [Spring] Springboot @RestController 404 에러 발생 시

[Springboot+Ajax] 데이터 통신

ITWeb/개발일반 2022. 4. 7. 15:43

Spring Domain, VO, Model

@Setter
@Getter
@ToString
public class SearchRequestModel {

    private PageModel pageModel;
    private long id;
}

@Setter
@Getter
@ToString
public class PagetModel {

    private int page;
    private int size;
    private String sort;
}

 

Spring RestController

@ResponseBody
@RequestMapping(
    value = "/api/search",
    method = RequestMethod.POST,
    produces = { MediaType.APPLICATION_JSON_VALUE }
)
public String search(
	@RequestBody SearchRequestModel m
) {
	return service.search(m)
}

 

Ajax

$.ajax({
    type: "POST",
    url: "/api/search",
    dataType: "json",
    contentType: "application/json",
    data: JSON.stringify({
        "pageModel": {
            "page": 1,
            "size": 20,
            "sort": "asc"
        },
        "id": 1
    }),
    success: function(res) {
    },
    error: function(res, status, e) {
    }
});

 

Ajax 요청 시 dataType, contentType 선언 없이 + @RequestBody 선언 없이 사용할 경우,

일반적인 POJO 스타일의 Data Binding 으로 처리가 됩니다. (Spring 에서는 자동으로 처리가 됩니다.)

또는

@RequestParam 을 이용해서 값을 전달 받을 수 있습니다.

 

오랜만에 화면 작업 하다 보니 이런것도 기억이 가물 가물 합니다.

:

[Docker] Spring Boot App 도커 적용

ITWeb/개발일반 2022. 3. 23. 10:49

Springboot 로 WAS 생성 후 이를 도커 기반으로 생성, 실행 하기 위해서 관련 내용 기록 합니다.

 

관련 문서)

https://spring.io/guides/gs/spring-boot-docker/
https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/

 

과정)

1. 프로젝트를 빌드 해서 bootJar 를 생성 합니다.

보통 build/libs 에 생성이 됩니다.

 

2. Dockerfile 을 생성 합니다.

여기서 bootJar 를 ADD 해야 하는데 Dockerfile 과 같은 Depth 에 위치 하거나 하위에 위치해야 합니다.

상위에 bootJar 가 있을 경우 permission denied 에러가 발생 합니다.

 

3. Image 생성을 합니다.

$ docker build -t 이미지명:태그 .

태그 정보는 jenkins 에서 build number 를 부여 하거나 운영 규칙을 정해서 관리 합니다.

registry 를 운영하고 있으면 생성된 이미지를 등록 합니다.

 

4. docker-compose.yml 을 생성 합니다.

registry 를 운영하고 있으면 registry 에서 이미지를 받아 옵니다.

 

관련 예제 코드들은 위 문서에 잘 나와 있으니 참고 하면 됩니다.

 

아래는 그냥 참고용으로 올려 봅니다.

build.gradle)
...중략...
bootJar {
  destinationDirectory=file('docker/libs')
  enabled = true
}
...중략...

$ export TAG=1.0.0
$ docker build -t boot-app:$TAG .


Case 1) docker/Dockerfile
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=./libs/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

Case 2) docker/Dockerfile
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=./libs/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT java \
-jar app.jar

Case 3) docker/Dockerfile
ENV heapSize="-Xms2048 -Xmx2048m"
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=./libs/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","${heapSize}","-jar","/app.jar"]

Case 4) docker/Dockerfile
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=./libs/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT java \
${heapSize} \
-jar app.jar

ENTRYPOINT 추가 옵션)
-Djava.security.egd=file:/dev/./urandom \
-Dspring.profiles.active=local


docker-compose) docker/docker-compose.yml
version: '3.7'

services:
  boot-app:
    container_name: boot-app
    image: boot-app:${TAG}
    environment:
      - TZ=Asia/Seoul
      - env=local
      - "heapSize=-Xms2048m -Xmx2048m"
    ports:
      - "8080:8080"
    volumes:
      - ./logs:/home/appuser/logs
    sysctls:
      - net.core.somaxconn=65000
    restart: on-failure

 

:

[Elasticsearch] LLRC + Springboot 성능 튜닝 팁

Elastic/Elasticsearch 2021. 12. 7. 09:14

대부분의 성능 이슈는 서버 엔진 보다는 클라이언트 단에서 사용을 잘 못 하는 경우가 많이 있습니다.

 

Low Level Rest Client 와 Springboot 조합으로 API 개발 시 튜닝 요소를 조금 정리 합니다.

나중에 또 기억 못할 것 같으니...

 

RestClientBuilder 에 보면 아래와 같이 기본 설정이 되어 있습니다.

public static final int DEFAULT_MAX_CONN_PER_ROUTE = 10;
public static final int DEFAULT_MAX_CONN_TOTAL = 30;

이 기본 값으로 그냥 사용하게 되면 너무 리소스를 제한적으로 사용하기 때문에 성능이 제대로 나오지 않게 됩니다.

해당 값을 적절하게 튜닝을 하셔야 하는데 모든 케이스에 다 적용 가능한 부분은 아니지만 그래도 가늠 할 수 있는 기준 정도로는 사용이 가능 할 것 같아 공유 합니다.

분석 결과는 Core 1 개당 setMaxConnPerRoute 설정 시 25 개씩이 최적 값으로 보입니다.
4 core 짜리면 4 x 25 = setMaxConnPerRoute(100)

 

아래는 실제 코드 내부에 작성 되어 있는 코멘트를 보여 드리기 위해 캡쳐 했습니다.

HttpAsyncClientBuilder httpClientBuilder = HttpAsyncClientBuilder.create().setDefaultRequestConfig(requestConfigBuilder.build())
  //default settings for connection pooling may be too constraining
  .setMaxConnPerRoute(DEFAULT_MAX_CONN_PER_ROUTE).setMaxConnTotal(DEFAULT_MAX_CONN_TOTAL)

 

코드에서도 동일하게 기본 설정은 너무 제한적일 수 있다고 되어 있습니다.

 

Embedded Tomcat 에서의 기본 Max Connection 은 8192 개 입니다.

Tomcat 과 HttpClient 그리고 Elasitcsearch 에 대한 각각의 Connection, Thread Count 를 잘 조정 하셔야 성능을 최적화 할 수 있습니다.

 

추가적으로 Connection 과 Route 의 비율은 10:1 정도가 적절해 보입니다.

 

아래는 Tomcat 기본 설정 내용입니다.

- Embedded Tocmat 의 설정 중
    acceptCount 는 기본 100 개 이며 이 설정은 maxConnection 에 다다랐을 때 OS 레벨에서 큐잉 하게 되는 값 입니다.
    maxConnections 는 기본 8192 개 이며 NIO/NIO2 를 사용 하며, -1 로 설정 시 카운팅 하지 않습니다. (unlimited)
    maxThreads 는 기본 200 개 이며 connection 당 생성 가능한 최대 thread 수 입니다.
    BIO 일 경우 maxConnections 와 maxThreads 값은 같아야 합니다.


정답은 없으나 시스템 리소스 상황에 맞춰서 최적 값을 찾아 내는게 제일 중요 합니다.
위에 설정 방식이나 값이 최적 값이 아니며 상황에 맞춘 최적 값이고 다른 환경에서는 튜닝 포인트가 된다고 보는게 좋을 것 같습니다.

시스템의 ulimit 설정을 꼭 확인 하고 사용하는 stack 의 default 값도 꼭 확인 하고 사용 합시다.

성능 최적화를 위해 함께 살펴 봐야 하는 소스 코드는 

Java NIO, Executor
Tomcat Connector
Http Client (Components)
Elasticsearch RestClient

 

:

[Spring] bean name conflict resolve.

ITWeb/개발일반 2021. 11. 30. 12:17

간단하게는 명시적으로 선언을 해주시면 됩니다.

 

서로 다른 패키지에 같은 이름의 class 가 존재 할 경우 발생 할 수 있습니다.

이런 경우 아래와 같이 선언해 주시면 됩니다.

 

@RestController("cat.RestHealthController")

@Service("cat.service.HealthService")

 

@RestController("cluster.RestHealthController")

@Service("cluster.service.HealthService")

 

:

[Spring] @Autowired vs @RequiredArgsConstructor

ITWeb/개발일반 2021. 11. 30. 10:36

Spring DI 선언에 사용 합니다.

 

[Spring Autowired Annotation]

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/annotation/Autowired.html

 

[Lombok RequiredArgsConstructor Annotation]

https://projectlombok.org/api/lombok/RequiredArgsConstructor.html

 

:

[Spring] Intellij Community + Springboot Profile 활용

ITWeb/개발일반 2021. 10. 20. 16:43

Intellij Community + Spring Boot Framework Profiles

intellij 에서 바로 springboot application 을 실행 시킬 때 환경 설정 파일을 분리해서 사용하기 위한 내용입니다.
Intellij Community 같은 경우 Ultimate 이랑 다르기 때문에 아래와 같은 방법으로 사용 하시면 됩니다.

application.yml 내 "---" 을 이용한 방식은 검색 해 보시면 많이 나와 있으니 넘어 가겠습니다.
아래 방식이 제가 하고 싶은 방법이라서 기술 합니다.

resources/
  + application.yml
  + application-local.yml

Edit Configuration -> Build and run 에서 Modify options 를 선택해서 add VM options 선택 -> -Dspring.profiles.active=local 입력
또는
Environment variables 에서 아래 key=value 입력 합니다.
spring.profiles.active=local

이와 같이 설정 하고 Application 을 실행 시켜 보시면 동작하는 걸 확인해 볼 수 있습니다.

 

:

[SpringBoot] 깡통 프로젝트 생성 후 실행 시 에러 (Error creating bean with name 'dataSource' defined in class path resource)

ITWeb/개발일반 2021. 9. 16. 17:26

springboot 프로젝트 만들어야 할 때 이용 합니다.

https://start.spring.io/

필요한 dependency 추가해 주고 로컬로 다운로드 받아 바로 실행 시켜 봅니다.

근데 깡통임에도 불구하고 에러가 발생을 했습니다.

 

mybatis 를 추가 했을 경우 application.yml 에 datasource 관련 설정을 하지 않게 되면 발생 하는 에러 입니다.

아래와 같이 설정을 추가 하고 build.gradle 에 mysql connector lib 도 추가해 주고 실행 하면 에러가 없어 집니다.

 

[error logs]
2021-09-16 17:24:18.201  WARN 76669 --- [  restartedMain] ConfigServletWebServerApplicationContext : 
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: 
Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: 
Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: 
Factory method 'dataSource' threw exception; 
nested exception is org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: 
Failed to determine a suitable driver class
2021-09-16 17:24:18.205  INFO 76669 --- [  restartedMain] o.apache.catalina.core.StandardService   : Stopping service [Tomcat]

[application.yml]
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/...
    username: ${USER}
    password: ${PASSWORD}
    
[build.gradle]
implementation group: 'mysql', name: 'mysql-connector-java', version: '8.0.26'

 

:

[Spring] Event Pub/Sub 기능 예제

ITWeb/개발일반 2021. 3. 3. 11:23

Spring 을 이용해서 간단한 Pub/Sub 기능을 구현 할 수 있는 예제 입니다.

 

관련 Class & Annotation)

ApplicationEventPublisher

@EventListener

 

Pub & Sub 을 위한 Topic Payload)

CustomEventTopicPayload

 

Subscriber Class)

CustomEventSubscriber

 

Code Example)

HelloController : Publisher

@Controller
public class HelloController {

  @Autowired
  ApplicationEventPublisher eventPublisher;

  @GetMapping ("/poc/hello")
  public String hello() {

    eventPublisher.publishEvent(new CustomEventTopicPayload(this, 100));

    return "poc/hello";
  }
}

 

CustomEventSubscriber - Subscriber

@Component
@Log4j2
public class CustomEventSubscriber {

  @EventListener
  public void onEventListener(CustomEventTopicPayload topic) {
    log.debug("{} Topic payload: " + topic.getData(), Thread.currentThread().toString());
  }
}

 

CustomEventTopicPayload - Topic Payload

@Getter
@Setter
public class CustomEventTopicPayload {
  private Object source;
  private int data;

  public CustomEventTopicPayload(Object source) {
    this(source, 0);
  }

  public CustomEventTopicPayload(Object source, int data) {
    this.source = source;
    this.data = data;
  }
}

 

아래 간략한 코드 스니핑은 스프링 4.2 이전 방식 입니다.

public class CustomEventTopicPayload extends ApplicationEvent {}

public class CustomEventSubscriber implements ApplicationListener<CustomEventTopicPayload>{}

 

:

[Spring] 멀티모듈 프로젝트 jar SKIPPED

ITWeb/개발일반 2021. 2. 22. 18:24

intellij community 를 사용하고 있는데 다른 사람은 다 되는게 나만 안되어서 설정을 고쳐서 해결 했습니다.

다른 사람들은 intellij ultimate 사용 하고 있습니다.

 

Multi module web 프로젝트 실행 시 submodule 만 동작해서 원인을 찾아 보고 해결했습니다.

 

원인은)

> Task :base:compileJava UP-TO-DATE
> Task :base:processResources NO-SOURCE
> Task :base:classes UP-TO-DATE
> Task :base:jar SKIPPED
> Task :custom:compileJava UP-TO-DATE
> Task :custom:processResources NO-SOURCE
> Task :custom:classes UP-TO-DATE

 

해결은)

project(":base") {
  jar{
    enabled = true
  }
}

 

근데 왜 나만 저렇게 설정을 해줘야 하는지는 못 찾았습니다.

아시는 분은 제보 좀...

:

[Spring] Springboot @RestController 404 에러 발생 시

ITWeb/개발일반 2021. 1. 28. 15:11

분명 유저 불량입니다.

보통 Annotation 선언하고 빨갱이도 없고 정상적으로 실행도 되었는데 REST API 호출 시 404 Not found 가 떨어 지는 경험을 해 보신 분들이 계실 것 같습니다.

 

특히 쥬니어 분들 중에 많을 것 같고요.

 

딱 봐도 Component Scan 이 정상적으로 되지 않았기 때문인데 코드를 보면 아무 문제가 없어 보입니다.

제가 본 이슈는 Main Application Class 파일의 위치가 잘못 되어 있는 것을 확인 했습니다.

 

tree 구조로 예를 들면) 틀린 예

ㄴ com.abc.app

MainApplication.java

ㄴ com.abc.api

ApiRestController.java

 

이렇게 되면 MainApplication 상위에 있는 class 는 scan 이 되지 않습니다.

반드시 MainApplication  하위로 패키지와 클래스를 이동 시켜 주셔야 합니다.

그게 아니라면 별도 @ComponentScan 이용해서 수동 등록을 해주시는 것도 방법 일 것 같습니다.

 

tree 구조로 예를 들면) 맞는 예

ㄴ com.abc.app

MainApplication.java

ㄴ com.abc.app.api

ApiRestController.java

 

: