반응형

스프링부트 사용하면서부터 RestTemplate을 많이 사용하여 API개발을 해왔었다.

하지만 최근에 알게된 사실은 블로킹 API로 리액티브 기반의 애플리케이션에서의 성능을 떨어트리는 원인이 될 수 있다는 걸 알게 되었다. 또한 Spring5.0버전부터는 RestTemplate은 유지모드로 변경되고 향우 deprecated될 예정이라고 한다.

따라서 대안으로 Spring에서는 WebClient사용을 권고하고 있으며 다음과 같은 장점이 있다.

  • Non-blocking I/O
  • Reactive Streams back pressure
  • High concurrency with fewer hardware resources
  • Functional-style, fluent API that takes advantage of Java 8 lambdas
  • Synchronous and asynchronous interactions
  • Streaming up to or streaming down from a server

WebClient에 대한 자세한 사용법에 대해서 알고 싶다면 아래의 블로그 글을 참고하자.

medium.com/@odysseymoon/spring-webclient-%EC%82%AC%EC%9A%A9%EB%B2%95-5f92d295edc0

 

Spring WebClient 사용법

Spring 어플리케이션에서 HTTP 요청을 할 땐 주로 RestTemplate 을 사용했었습니다. 하지만 Spring 5.0 버전부터는 RestTemplate 은 유지 모드로 변경되고 향후 deprecated 될 예정입니다.

medium.com

 

스프링공식문서

www.baeldung.com/spring-webclient-resttemplate

 

Spring WebClient vs. RestTemplate | Baeldung

Learn how to make server-side HTTP calls using WebClient and RestTemplate.

www.baeldung.com

 

반응형
반응형

스프링부트에서 JavamailSender사용시 sendMail부분에서 다음과 같은 에러가 발생

org.springframework.mail.MailSendException: Mail server connection failed; nested exception is javax.mail.NoSuchProviderException: No provider for SMTP. Failed messages: javax.mail.NoSuchProviderException: No provider for SMTP at org.springframework.mail.javamail.JavaMailSenderImpl.doSend(JavaMailSenderImpl.java:446) ~[spring-context-support-5.1.2.RELEASE.jar!/:5.1.2.RELEASE] at
.
.
.
Caused by: javax.mail.NoSuchProviderException: No provider for SMTP
at javax.mail.Session.getProvider(Session.java:545) ~[javax.mail-1.6.2.jar!/:1.6.2] at 
.
.

 

소스코드

    @Bean
    public JavaMailSenderImpl mailSender() {
        JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();

        javaMailSender.setProtocol("SMTP");
        javaMailSender.setHost("127.0.0.1");
        javaMailSender.setPort(25);

        return javaMailSender;
    }

문제의 원인은 javaMailSender.setProtocol("SMTP"); 이부분이였다.

setProtocol의 "SMTP"를 "smtp" 소문자로 변경해주면 해결된다.

해결책

"SMTP" => "smtp"

이유

JavaMailSenderImpl 파일을 들어가보면 알 수 있다. 내부에 DEFAULT_PROTOCOL 이 소문자로 할당되어있다.

public class JavaMailSenderImpl implements JavaMailSender {
    public static final String DEFAULT_PROTOCOL = "smtp";
    

항상 문제가 발생했을 때 문제 해결에 그치지 말고 이유에 대해서도 꼭 짚고 넘어가도록 하자!!!!

문제 해결보다 중요한게 원인 파악 이라고 생각한다.

반응형
반응형

스프링부트에서 메일 발송 기능 구현 중 다음과 같은 에러가 발생하였다.

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mailService': Unsatisfied dependency expressed through field 'javaMailSender'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.mail.javamail.JavaMailSender' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:596) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE] 
.
.
.
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.mail.javamail.JavaMailSender' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1646) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1205) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1166) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:593) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]

 

소스코드

기본적인 maven dependency추가 후 @Autowired했음

 

문제해결

@Bean으로 다음과 같이 protocol, host, port 지정 해줌

    @Bean
    public JavaMailSenderImpl mailSender() {
        JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();

        javaMailSender.setProtocol("smtp");
        javaMailSender.setHost("127.0.0.1");
        javaMailSender.setPort(25);

        return javaMailSender;
    }
반응형
반응형

스프링부트 with JPA 프로젝트 작업중 신기한게 로컬환경에서는 에러가 안났는데 alpha, real환경에만 배포하면 위와 같은 에러 메세지가 나왔다....

Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Either use @Param on all parameters except Pageable and Sort typed once, or none at all!

문제의 원인이 무었이었는고 하니...

JPA 에서 매개변수 2개를 받는 메서드에 한 변수에만 @Param을 지정해서 사용하여서 발생하였다...

jobId 매개변수에도 @Param을 명시적으로 주니 정상적으로 해결 되었다.

void upsertAnalysisData(@Param("jobId") int jobId, @Param("audience") AudienceAnalysis audienceAnalysis);

혹시나 비슷한 에러가 발생한다면 JPA Repository부분에 특정 매개변수에만 @Param을 주어서 사용하진 않았는지 확인해보자!

반응형
반응형

스프링부트의 기본 컨테이너는 톰캣임을 알고 있었는데 이를 제외하고

다른 컨테이너를 사용하기 위한 방법에 대해 간단히 포스팅해본다. 

 

spring-boot-starter-web을 사용하게 되면 내부에 spring-boot-starter-tomcat을 포함하게 된다.

의존성 관계를 보면 알 수 있다.

따라서 다른 컨테이너를 사용하고 싶다면 spring-boot-starter-web의존성에서 tomcat을 exclusion시켜주어야 한다.

참조 : https://docs.spring.io/spring-boot/docs/current/reference/html/howto-embedded-web-servers.html

위와 같이 tomcat을 exclusion시켜주고 jetty의존성을 주입하게 되면 컨테이너로 jetty를 사용할 수 있다.

 

자세한 내용은 spring docs를 참고하자!

https://docs.spring.io/spring-boot/docs/current/reference/html/howto-embedded-web-servers.html

반응형
반응형

스프링부트 프로젝트 생성 후 어플리케이션을 실행시켰는데 에러없이 실행되자마자 종료되는 경우가 있다. 

 


Process finished with exit code 0

라고 뜨며 어플리케이션이 바로 종료되어버린다.

스프링부트는 임베디드톰캣 기반으로 실행되는데 임베디드컨테이너의 클래스패스를 못잡아줘서 그런 것 같다.

따라서 메이븐에 다음과 같이 의존성을 추가해준다.

<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-web</artifactId>

</dependency>

<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-web</artifactId>

</dependency>

 

반응형
반응형

보통 웹서비스에서 포트를 두 개 사용하는 경우는 http, https를 사용하는 경우이다.


보통은 ssl작업은 앞단에 웹서버(apache, nginx)를 두지 처리하는데 springboot만으로도 처리가 가능하다.


application.properties에 server.port=8080을 설정해두고 


추가로 8082 포트를 사용하고자 하면 다음과같이  ConfigurableEmbeddedServletContainer에


Connector에 추가로 사용하고자 하는 포트(port)를 설정해 셋팅해주면 된다.




이렇게 설정하고 실행시켜서 테스트해보면


localhost:8080, localhost:8082로 모두 서비스를 사용할 수 있다.


어떻게 언제 사용하냐고????


보통은 http, https 처리하는 경우, 그 외에는 사실 잘모르겠다...

반응형
반응형


웹 작업을 할 때 jsp내의 문구라던지 구조를 변경하고 확인해야하는데 실시간으로 반영이 안되면 무척이나 성가시지요...


빌드다시해줘야하고.....시간은 시간대로 잡아먹고...


SpringBoot를 쓰고 계신다면 application.properties에 다음과 같이 추가해 주세요.


server.jsp-servlet.init-parameters.development=true


추가 이후에는 어플리케이션 재시작 없이 바로 웹에 반영되는 것을 확인할수 있다.

반응형
반응형

스프링부트(Springboot) 사용시 java.lang.IllegalArgumentException: An invalid domain Error 해결하기


스프링에서 쿠키에 setDomain을 할 경우 현재 서버의 도메인 및 상위 도메인 외에 다른 도메인을 셋팅하게 되면 에러가 발생한다.


서버 도메인이 test.com인데 다음과 같이 쿠키에 setDomain을 하게되면


cookie.setDomain(".toast.com");


다음과 같은 에러가 발생한다.


java.lang.IllegalArgumentException: An invalid domain [.toast.com] was specified for this cookie

at org.apache.tomcat.util.http.Rfc6265CookieProcessor.validateDomain(Rfc6265CookieProcessor.java:183)

at org.apache.tomcat.util.http.Rfc6265CookieProcessor.generateHeader(Rfc6265CookieProcessor.java:125)

at org.apache.catalina.connector.Response.generateCookieString(Response.java:989)

at org.apache.catalina.connector.Response.addCookie(Response.java:937)

at org.apache.catalina.connector.ResponseFacade.addCookie(ResponseFacade.java:386)

at com.nhnent.demonaid.cms.CookieMatchingServiceController.getAdRequestFromMedia(CookieMatchingServiceController.java:80)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

at java.lang.reflect.Method.invoke(Method.java:498)

at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:220)

.

.

.



[ 원인 ] 


tomcat8 버전 이상에서는 Cookie Header를 파싱하는 기본 CookieProcessor가 RFC6265를 기반으로 하고 다음과 같은 속성을 같는다.

5.2.3.  The Domain Attribute

   If the attribute-name case-insensitively matches the string "Domain",
   the user agent MUST process the cookie-av as follows.

   If the attribute-value is empty, the behavior is undefined.  However,
   the user agent SHOULD ignore the cookie-av entirely.

   If the first character of the attribute-value string is %x2E ("."):

      Let cookie-domain be the attribute-value without the leading %x2E
      (".") character.

   Otherwise:

      Let cookie-domain be the entire attribute-value.

   Convert the cookie-domain to lower case.

   Append an attribute to the cookie-attribute-list with an attribute-
   name of Domain and an attribute-value of cookie-domain.


Domain값 맨 앞자리에 "."을 붙일 경우 "."을 제거하고 파싱하게 된다.


[ 해결 ]

SpringBoot를 사용하고 있는 경우(Embedded Tomcat) 다음과 같은 설정을 해주면 된다. 스프링부트 자바 config클래스에 넣어주면 된다.




[ reference ]

https://jistol.github.io/java/2017/08/30/tomcat8-invalid-domain/

http://hyunc87.tistory.com/34

반응형

+ Recent posts