728x90

  일정 시간 간격 또는 정해진 시간에 실행되도록 하는 기능이다.

기본예제코드

스케줄러 클래스.

클래스에 @Component를 달고 메서드에는 @Scheduled를 단다.

비동기로 실행되어야 하는 업무는 @Async를 단다.

@Component
public class ExampleScheduler {
	/**
	 * 생성자.
	 */
	public ExampleScheduler() {
		super();
	}

	/**
	 * 스케줄 테스트하기.
	 */
	@Scheduled(cron = "0/60 * * * * ?")
	public void testCron() {
		System.out.println("(cron = \"0/60 * * * * ?\") 시스템 시간을 기준으로 1분 마다 주기적으로 실행한다.");
	}

	/**
	 * 스케줄 테스트하기.
	 */
	@Scheduled(fixedRate = 8000)
	public void testFixedRate() {
		System.out.println("(fixedRate = 8000) 다른 스케줄 작업 완료 여부와 상관 없이 8000ms마다 실행한다.(단, 스케줄러풀 필요.)");
	}

	@Scheduled(fixedDelay = 2000)
	public void testFixedDelay() {
		final String prefix = DateFormatUtils.format(new Date(), "ddHHmmss");
		for (int i = 0; i < 10; i++) {
			System.out.println(prefix + "-" + i + ". 비동기가 제대로 작동하는지 확인하기 위해, 의도적으로 장시간 실행되도록 함.");
			try {
				Thread.sleep(1000L);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("(fixedDelay = 2000) 이 작업이 끝나면, 2000ms 뒤에 다시 실행한다.");
	}

	/**
	 * 비동기 스케줄 테스트하기.
	 */
	@Scheduled(fixedRate = 4000)
	@Async
	public void testFixedRateAysnc() {
		System.out.println("(fixedRate = 4000 @Async) 다른 스케줄 작업 완료 여부와 상관 없이 4000ms마다 실행한다.(단, 스케줄러풀 필요.)");
	}
}

“dispatcher-servlet.xml”에 설정들 추가.

  루트 beans에 task와 그 스키마 정보를 추가한다.

  그리고 task가 인식되도록 어노태이션에서 읽어들이도록 ‘<task:annotation-driven/>’를 추가한다.

<beans xmlns="http://www.springframework.org/schema/beans" …(생략)...
    xmlns:task="http://www.springframework.org/schema/task"
    …생략…
    xsi:schemaLocation="...
        http://www.springframework.org/schema/task     http://www.springframework.org/schema/task/spring-task.xsd
">

    <!-- 스케줄러 -@Scheduled가 있는 @Component 찾기 -->
    <task:annotation-driven scheduler="jobScheduler"/>
    <!-- 스케줄러 -@Async를 위한 스케줄러풀 설정 -->
    <task:scheduler id="jobScheduler" pool-size="10"/>

    …생략…
</beans>

  ‘<task:annotation-driven/>’의 스케줄러 컴포넌트 스캔 범위도 ‘<context:component-scan>’의 ‘base-package’에 설정한 스캔범위에 들어있어야 함은 동일하니 패키지 경로에 주의하자.

해설

  스케줄들은 실행시간이 되어도 다른 스케줄이 실행되는 중이면 끝날 때까지 대기하게 된다. 만약 반드시 정해진 시간에 실행되어야 하는 스케줄이라면 문제 될 것이다. 이를 위해 비동기로 실행시킬 수 있다.

  비동기는 스케줄 메서드에 @Async를 붙이면 된다. 단, 그냥 붙이기만 하면 실제로는 비동기로 실행이 되지 않는다. 비동기로 실행시키려면 [스케줄러 풀]이 필요하다.

참고 링크

반응형
728x90

한국투자증권 OpenAPI를 사용하려고 코딩을 했는데, 정작 실행을 하자 [javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target]라는 길고 긴 예외가 발생했습니다.

검색을 해보니 원인이 여러가지일 수 있다고 하는군요. 일단 순서대로 첫번째 것부터 진행해봤는데, 첫번째 걸로 해결이 되버렸습니다.

*해결책 링크 : [Java 에서 ValidatorException 등 인증서 관련 에러 해결 - keystore에 SSL/TLS 인증서를 import 하기]

링크의 내용을 그냥 따라하면 되는데, 다만 [6]번에서 keytool이 어디에 있는지 설명이 없어서 약간 해맸습니다. 혹시나 해서 자바 설치 폴더의 bin 폴더를 살펴보니 거기에 있더군요.(설정에 패스가 잡혀 있으면 문제 없겠지만, 저처럼 안 잡혀 있으면 해당 경로에 맞춰서 입력해주면 됩니다.)

덕분에 잘 실행되어서 계속해서 개발해봐야겠습니다.

반응형
728x90

이번에는 @ControllerAdvice입니다. 개인적으로 가장 효율적인 방법이라고 봅니다.


@ControllerAdvice

ControllerAdvice가 모든 컨트롤러에서 발생한 예외를 맡습니다.

예제

<web.xml>

	<servlet>
		<servlet-name>action</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/config/egovframework/springmvc/dispatcher-servlet.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

<dispatcher-servlet.xml>

<bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver"></bean>

<ControllerAdvice 클래스>

@ControllerAdvice
public class ExampleAdvice extends ResponseEntityExceptionHandler {
	/**
	 * 로그.
	 */
	private static final Log LOG = LogFactory.getLog(ExampleAdvice.class);

	@ExceptionHandler(Throwable.class)
	public String handleException(final Exception e, Model model) {
		LOG.error("Throwable 예외 기록.", e);
		model.addAttribute("msg", "오류 발생 시 메시지 추가 테스트입니다.");
		return "/cmmn/egovError";
	}

	@ExceptionHandler(ExampleForbiddenException.class)
	public String handleException(final ExampleForbiddenException e, Model model) {
		LOG.error("ExampleForbiddenException 예외 기록.", e);
		model.addAttribute("msg", "오류 발생 시 메시지 추가 테스트입니다.");
		return "/cmmn/egovError";
	}
}

장단점 설명

Controller에 Advice를 줄 용도로 만든 클래스에 [@ControllerAdvice]어노태이션을 붙인다. 클래스 내의 오류 처리 메서드에는 [@ExceptionHandler]어노태이션을 붙인다.

[@ExceptionHandler]어노태이션이 붙은 메서드가 동작하게 하려면 [ExceptionHandlerExceptionResolver]를 반드시 설정해야 한다.(Spring 3.1 이후에 DispatcherServlet에 기본으로 설정되어 있다고 하는데, 동작하지 않을 때는 명시적으로 설정하자.)

만약 특정 컨트롤러에서만 독자적인 오류 처리가 필요한 경우, 해당 컨트롤러 내에 예외 처리 메서드를 작성하고 [@ExceptionHandler]어노태이션을 붙이면 된다. ControllerAdvice의 [@ExceptionHandler]보다 컨트롤러 내의 [@ExceptionHandler]가 우선된다.

장점 : 전체 컨트롤러에서 발생하는 오류를 처리해주는 기능을 클래스 하나로 해결할 수 있다. 오류 로그를 남겨도 좋고, 다른 추가 처리를 해도 좋다. 특정 컨트롤러에서만 독자적인 오류 처리가 필요한 경우 분리시킬 수 있는 것도 장점.

단점 : 별달리 없다.

총평 : 가성비가 좋다. -_-)b

참고

반응형
728x90

이번에는 ExceptionResolver 관련 간단한 정리입니다. 미리 준비되어 있는 ExceptionResolver가 몇 종류 있는데, 개인적으로는 ExceptionHandlerExceptionResolver만 쓸 줄 알아도 충분하다고 봅니다.


ExceptionResolver

DispatcherServlet에 ExceptionResolver를 선언하여 에러 발생 시 해당 ExceptionResolver가 처리하게 하는 방식이다.

예제

<web.xml>

	<servlet>
		<servlet-name>action</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/config/egovframework/springmvc/dispatcher-servlet.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

<dispatcher-servlet.xml>

<bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver"></bean>

<Controller 클래스>

	@ExceptionHandler({ IllegalArgumentException.class, ExampleException.class })
	@ResponseStatus(code = HttpStatus.BAD_REQUEST, reason = "Some parameters are invalid")
	public void onBadRequestException(final RuntimeException exception) {
		LOG.error("!오류 핸들러가 실행!", exception);
	}

[ExceptionHandlerExceptionResolver]는 예외 발생 시 [@ExceptionHandler]어노태이션이 붙은 메서드가 처리하게 한다.

장단점 설명

ExceptionResolver 클래스는 추상클래스[AbstractHandlerExceptionResolver]를 상속받거나, 인터페이스[HandlerExceptionResolver]를 구현하여야 한다. 두 경우 모두 메서드[resolveException]가 구현되어야 한다.

메서드[resolveException]은 다음과 같은 특징이 있다.

  • 인자로 Exception을 받는다. 예외를 로그에 남기는 등의 처리가 가능하다.
  • 반환형이 ModelAndView다. 이를 통해 출력할 뷰를 제어할 수 있다.

장점 : 로그를 남기는 등 추가 처리가 가능하다.

단점 : 별달리 없다.

총평 : 미리 지원해주는 ExceptionResolver가 몇 종류 있어서, 알아보고 사용하면 된다. 없으면 직접 상속받거나 구현한 클래스를 사용하면 된다. 다만 개인적으로는 ExceptionHandlerExceptionResolver와 @ControllerAdvice 연계가 가장 가성비가 좋다고 생각한다. @ControllerAdvice에 대해서는 다음에 설명한다.

참고

반응형
728x90

그 전부터 에러페이지 관련하여 한 번 정리하고 싶었는데, 이번에 마침 관련 업무를 할 일이 있었어서 나눠서 정리해보려 합니다.

어노태이션[@ResponseStatus]

예외 클래스 자체에 응답 상태 코드를 선언하여, web.xml의 에 매핑하는 방식이다.

예제

<예외 클래스>

@ResponseStatus(value = HttpStatus.FORBIDDEN)
public class ExampleForbiddenException extends RuntimeException {

	//…이하 생략…
}

위와 같이 예외 클래스에 응답코드를 선언해두고, 처리 로직에서 해당 예외를 던진다.

<처리 클래스>

	@GetMapping(value = "/example/error/throwExampleForbiddenException.do")
	public String throwException(final HttpServletResponse response) {
		if (true) {
			throw new ExampleForbiddenException("@ResponseStatus가 HttpStatus.FORBIDDEN으로 설정되어 있다.");
		}

		return "/example/fakeView"; // 여기는 실행되지 않는다.
	}

<web.xml>

	<error-page>
		<error-code>403</error-code>
		<location>/WEB-INF/jsp/example/error/forbiddenError.jsp</location>
	</error-page>​

장단점 설명

장점 :

  • 쉽고 간단하다. (예외에 응답 상태 코드를 지정하여, 바로 매핑된 에러 페이지를 바로 연결하면 끝)
  • ExceptionResolver가 없어도 동작한다.
  • ExceptionResolver의 종류에 따라서는 @ResponseStatus를 이용하기도 한다.

단점 : 로그 남기기 등의 추가 처리를 일원화하기 어렵다.

총평 : 오류가 나도 해당 정보를 확인할 수 없다는 점 때문에 단독으로 쓰일 일은 별로 없다.

참고

반응형

+ Recent posts