2008년 3월 4일 화요일
JCO 컨퍼런스에서 사용되었던 OSGi 자료
JCO컨퍼런스에서 사용되었던 SpringDM for OSGi 자료입니다.
출처: http://toby.epril.com/?p=366
2008/03/04 - [자바 어플리케이션/Spring] - OSGi 시작할 때 참고 하기 좋은 자료들
2008/01/27 - [자바 어플리케이션/Spring] - OSGi를 위한 Spring Dynamic Modules 릴리즈
OSGi 시작할 때 참고 하기 좋은 자료들
1. 가장 이해하기 쉽고 간결한 Neil Barlett 의 Getting Started with OSGi.
2. SpringDM(OSGi)의 핵심개발자인 Costin Leau가 쓴 Creating OSGi Bundles.
3. Apache Felix에서 제공하는 Apache Felix OSGi Tutorial.
자바에서 손뗄려고 다짐했건만 이렇게 자바 자료를 찾고 있는 나... OTL...
2008년 1월 27일 일요일
OSGi를 위한 Spring Dynamic Modules 릴리즈
OSGi ... 예전 모바일 자바에서 많이 들었었던 용어인데, 이렇게 Spring에서까지 언급이 되어지니 다시금 자료를 찾아보는 시간을 갖게 만드네요.
OSGi : Open Service Gateway Initiative 약자로써 "가전제품이나 보안시스템 등의 장치들을 인터넷에 접속하는 표준방식에 관한 산업계의 계획입니다" 라고 정의 되어있기는 하지만 저는 단순히 기존에 서비스를 서버에서 내리지 않고도 실시간으로 설정파일에 대한 변경사항을 시스템에 적용시켜줄 수 있는 일종의 메커니즘이라고 생각합니다.
Spring 공식 웹사이트에서 읽어본데 의하면
"이런방식(OSGi 방식)으로 쓰여진 코드는 각 모듈에 대한 분리를 더 철처히 할 수 있도록 하며 또한 작동중인 시스템에 동적으로 모듈을 추가, 삭제, 업뎃 할 수 있게끔 한다. 이를 제외하고도 동시에 여러버전의 모듈을 디플로이 해주는 기능을 갖고 있다." 라고 하네요.
한마디로 여러모듈로 이루어진 F/W상에서 실시간으로 또는 동적으로 필요한 모듈을 올리고 내릴수 있다고 보면 될것 같습니다.
아직까지는 버젼이 1.0 이라 직접 프로젝트에 투입하여 사용하기는 시기상조라는 느낌이 들긴 하지만 지금까지 프로젝트를 해오면서 이런 기능들을 제공해주는 먼가가 있지 않을가 하는 생각도 많이 하게 되었습니다. 결국 OSGi (예전에도 많이 들어왔던 개념) 에 대한 Spring Dynamic Modules의 릴리즈로 이 모든 것이 가능 하게 되겠군요.
Spring DM 1.0 다운로드 링크
Spring DM 1.0 참고문서
Spring DM 1.0 JavaDOC
Spring DM 1.0 샘플 서비스들
2007년 12월 27일 목요일
Spring에서 Gmail SMTP서버를 이용하여 메일 보내기
단순 텍스트 메일이 아닌 MIME타입의 메일을 보내기 위해서는 오로지 Spring만으로 구현이 불가능 합니다. 여러가지 문서를 참고한 결과 Java Mail과 Spring을 적절히 활용하면 MIME 타입의 메일을 쉽게 보낼수가 있음을 파악할수 있었습니다.
Spring 클래스들을 살펴보면 JavaMail과의 연동 및 확장가능성을 지원해주기 위하여
JavaMailSenderImpl 과 MimeMessageHelper 등과 같은 다양한 클래스들을 지원해주고 있습니다.
일단 AbstractMailSender라는 추상화 메일 센더 클래스를 만듭니다.
import org.springframework.mail.javamail.JavaMailSender;
/**
* @author Leegun
*
*/
public abstract class AbstractMailSender
{
protected JavaMailSender sender;
public void setSender(JavaMailSender sender) {
this.sender = sender;
}
public abstract void sendMail( String to, String from,
String subject, String text ) throws MessagingException;
다음은 메일 인증을 담당하고 있는 JavaMailAuthenticator 클래스를 만듭니다.
기존에 Java에서 지원해주고 있는 메일 인증 모듈을 그대로 사용하기 위하여 JavaMailSenderImpl 클래스를 상속받아서 구현을 시도합니다.
import org.springframework.mail.javamail.JavaMailSenderImpl;
/*** @author Leegun
*
*/
public class JavaMailAuthenticator extends JavaMailSenderImpl
{
public JavaMailAuthenticator()
{
super();
Properties props = new Properties();
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.auth", "true");
this.setJavaMailProperties(props);
}
}
마지막으로 실제 전송해야 할 메일 내용및 To, From 과 같은 기본 사항들을 설정해줍니다.
MIME타입의 메일을 보내기 위하여 MimeMessageHelper 클래스를 사용합니다.
import javax.mail.internet.MimeMessage;
import org.springframework.mail.javamail.MimeMessageHelper;
/*** @author Leegun
*
*/
public class MimeMailSender extends AbstractMailSender
{
// 메일 전송시 오류가 발생하면 MessagingException을 던진다.
public void sendMail( String to, String from,
String subject, String text ) throws MessagingException
{
MimeMessage msg = sender.createMimeMessage();
// true를 세팅함으로써 메일 포맷의 다양화를 지원하겠다는것을 명시적으로 세팅해준다.
MimeMessageHelper helper = new MimeMessageHelper(msg, true, "utf-8");
helper.setTo(to);
helper.setFrom(from);
helper.setSubject(subject);
helper.setText(text);
sender.send(msg);
}
}
마지막으로 ApplicationContext 에 관련 빈들을 설정해줍니다.
<bean id="javaMailSender" class="mypackage.JavaMailAuthenticator">
<property name="host" value="smtp.gmail.com" />
<property name="port" value="465" />
<property name="protocol" value="smtps" />
<property name="username" value="계정아이디@gmail.com">
<property name="password" value="비밀번호"/>
</bean>
<bean id="mimeMailSender" class="mypackage.MimeMailSender">
<property name="sender">
<ref bean="javaMailSender"/>
</property>
</bean>
</beans>
실제 사용은 아래와 같이 하면 됩니다.
MimeMailSender sender = (MimeMailSender) ctx.getBean("mimeMailSender");
try {
sender.sendMail("받는 사람 메일주소", "보내는 사람 메일 주소", "핼러우 스프링", "핼러우 스프링? 응?");
} catch (MessagingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Spring 에서 Java Mail 사용시 에러문
ApplicationContext에서는 아래와 같이 설정을 했었다.
<bean id="javaMailSender"
class="com.nanumsem.nnserp.common.util.AuthenticatedJavaMailSender">
<property name="host">
<value>smtp.xxxx.com</value>
</property>
<property name="username">
<value>xxxxx</value>
</property>
<property name="password">
<value>xxxxx</value>
</property>
</bean>
<bean id="mimeMailSender" class="com.nanumsem.nnserp.common.util.MimeMailSender">
<property name="sender">
<ref bean="javaMailSender"/>
</property>
</bean>
</beans>
그런데 실제 Tomcat 기동시
java.lang.NoClassDefFoundError: javax/mail/MessagingException
이런 에러 문구가 뜨면서 javaMailSender 빈인스턴스 생성시 실패하게 된다.
분석한 결과 Spring내에는 실제 Mail처리 관련 jar파일이 포함이 되어있지 않다는것이다.
Spring에서 Mail관련 기능을 구현하기 위해서는 별도로 J2EE 에 포함된 mail.jar를 필요로 하고 있다.
sun에서 mail.jar를 다운로드 받아 WEB-INF/lib 속에 넣고 다시 빌드를 했더니 그제야 정상적으로 빈을 생성하면서 기동되였다.
2007년 11월 6일 화요일
Spring 과 iText를 연동하여 PDF 생성하기
실제 Spring MVC를 이용하지 않고 iText만 이용하여 고품질의 PDF문서를 생성할 수 있다.
하지만 이미 프로젝트내에 Spring MVC를 도입하여 사용을 하고 있는 상황이라면 별도로 MVC를 구성하는것 보다는 아예 Spring MVC를 이용하는것이 편하다.
Spring MVC와 iText를 연동하는데 아래와 같이 4가지 단계가 필요하다.
- web.xml에서 서블릿 선언 및 서블릿 맷핑을 한다.
- pdf-servlet.xml 에서 viewController와 실제 PDF 를 엑세스할 URL을 매퍼를 선언한다.
- viewController 클래스를 만든다.
- pdfView 클래스를 만든다.
web.xml에서 아래와 같이 pdf용 서블릿을 선언하고 서블릿 맵핑을 한다.
[code xml] <!-- PDF Servlet Definition -->
<servlet>
<servlet-name>config/pdf</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<!-- Servlet Mapping For PDF DispatcherServlet -->
<servlet-mapping>
<servlet-name>config/pdf</servlet-name>
<url-pattern>*.pdf</url-pattern>
</servlet-mapping>[/code] 서블릿 명을 config/pdf로 설정하였으므로 우리가 만들어야 할 pdf 서블릿 설정 파일명은 pdf-servlet.xml이 되겠다.
pdf-servlet.xml에서는 실제 pdf 페이지를 요청하였을때 호출할 컨트롤러를 매핑해주는 urlMapping 빈 및 호출될 컨트롤러를 선언해준다. [code xml] <beans> <bean id="beanNameViewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver" /> <bean id="viewController" class="org.prototype.common.controller.MultiDocumentController" /> <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/viewPDF.pdf">viewController</prop> </props> </property> </bean> </beans> [/code] viewController 클래스는 실제 MultiActionController를 상속 받고 있는데 이렇게 함으로써 하나의 Controller로써 다양한 문서의 출력이 가능하다.
2007년 10월 25일 목요일
Spring 컨테이너가 아닌곳에서도 Service 사용하기
프로젝트를 하다보면 간혹가다가 서블릿으로 일부 어플리케이션을 만들어야 할 필요가 있다.
특히나 파일 다운로드를 구현하다보면 더욱 그러하다.
또한 일반 서블릿을 제외하고도 라이브러리나 기타 다른 클래스에서 직접 특정된 어플리케이션의 서비스인스턴스를 받아서 처리하려면 여간 힘들지 않다.
이런 경우 보통은 ApplicationContext를 ThreadLocal 변수에 저장시켰다가 다른 곳에도 호출하면서 사용한다. 하지만 한가지 단점은 ThreadLocal 변수를 초기화하지 않은채 특정된 어플리케이션을 호출하면 ApplicationContext 인스턴스를 가져올수가 없게 된다.
사실 서블릿 컨텍스트에는 ApplicatioinContext 인스턴스를 가지고 있다. 하지만 이 경우 나의 관심사는 다른 여타의 빈즈보다는 특정된 서비스이다. 솔직히 말해서 아래에 첨부한 소스를 조금 변경하면 서비스 인스턴스가 아닌 다른 인스턴스도 가져올수 있다.
먼저 그럼 소스부터 첨부하겠다.
소스열기
import javax.servlet.ServletContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
/**
* @author Leegun
*
*/
public class SysUpfileServiceHelper {
private static final String SYSUPFILESERVICE_BEANID = "sysUpfileService";
public static SysUpfileService getBoardService(ServletContext ctx) {
WebApplicationContext wac = WebApplicationContextUtils
.getRequiredWebApplicationContext(ctx);
}
}
getBoardService 메소드가 static으로 선언되였으므로 별도로 SysUpfileServiceHelper 를 인스턴스화 할 필요는 없다.
위 소스에 대하여 간단하게나마 설명을 하자면 실제 Servlet에서 bean을 접근 할수가 없므로 WebApplicationContext 인스턴스를 통하여 접근을 시도한다.
WebApplicationContext 인스턴스를 받게 되면 우리가 접근하려고 하는 bean 네임만 주고 실제 bean 인스턴스를 리턴받아 온다. 사실 이 루틴은 아예 이런 빈을 사용하려는 클래스에 포함시켜서 사용할 수 있다. 하지만 여러 곳에서 이런 서비스를 빈을 필요로 하는 경우가 존재하기때문에 별도로 serviceHelper라는 클래스로 추출하였었다. 사용자는 실제 자신의 상황에 마추에 이부분 코딩을 해주면 된다.
2007년 9월 10일 월요일
AbstractWizardFormController 사용기
소프트웨어 설치시 보면 한방에 설치가 되여지는것이 아닌 여러단계에 거쳐서 설치가 이루어진다. 보통보면 다음을 클릭하여 다음단계로 이동하고 완료를 클릭하여 설치를 끝마친다.
Spring Web MVC에도 이와 흡사한 방식으로 처리해주는 Controller가 있다.
그것이 바로 AbstractWizardFormController이다.
AbstractWizardFormController는 SimpleFormController와 비슷하며 그 메소드 구성만 봐도 거의 엇비슷한것을 발견할수 있다.
AbstractWizardFormController와 기타 컨트롤러 사이의 구별점을 열거하면 다음과 같다.
다시말하자면 AbstractWizardFormController는 요청을 통해 전해지는 사용자 입력값으로 폼 객체를 자동으로 설정하는 HTTP 폼 컨트롤러이다. 요청마다 새로운 폼 객체 인스턴스를 사용할 수도 있지만, sessionForm 속성을 true로 설정하면, 여러 차례의 요청 가운데서 객체를 공유할 수도 있다.
public AbstractWizardFormController() {
// AbstractFormController sets default cache seconds to 0.
super();
// Always needs session to keep data from all pages.
setSessionForm(true);
// Never validate everything on binding ->
// wizards validate individual pages.
setValidateOnBinding(false);
}
- 폼 객체의 작용범위는 Session이며 sessionForm의 속성은 true이다. 왜냐면 여러페이지에 거쳐서 데이타를 손실없이 가지고 가야하니깐 request영역내에서만 데이타를 유지시키는것은 불가능한것이다.
- 또한 폼 데이타가 바인딩될때 데이타유효성체크를 하지 않는다. 즉 validateOnBinding속성이 false로 된다.
- 여러개 폼 뷰사이에서 전환이 가능하다.
- 상당히 명확한 웍프로세스 템플릿 메소드들을 가지고 있다. 예로, 처리를 완료할때는 processFinish()메소드를 호출하고 처리를 취소할때는 processCancel()메소드를 호출하면 된다.
위에 몇가지 사항들을 제외하고도 실제 해당 컨트롤러를 사용하기 위해서는 알아둬야 할점이 몇가지 있다.
/**
* Parameter triggering the finish action.
* Can be called from any wizard page!
*/
public static final String PARAM_FINISH = "_finish";
/**
* Parameter triggering the cancel action.
* Can be called from any wizard page!
*/
public static final String PARAM_CANCEL = "_cancel";
/**
* Parameter specifying the target page,
* appending the page number to the name.
*/
public static final String PARAM_TARGET = "_target";
/**
* Parameter specifying the current page as value. Not necessary on
* form pages, but allows to properly handle usage of the back button.
* @see #setPageAttribute
*/
public static final String PARAM_PAGE = "_page";
내부적으로 프로세스 플러우를 처리하는 문자열 상수를 가지고 있는데 그것들로는
_finish, _cancel, _target, _page이다.
_finish는 임의의 폼페이지에서 호출이 되여질 수 있으며 폼 wizard를 끝마치고 싶을 때 호출한다.
_cancel또한 임의의 폼페이지에서 호출이 되여질 수 있으모 폼 wizard를 취소하고 싶을 때 호출한다.
* Set the wizard pages, i.e. the view names for the pages.
* The array index is interpreted as page number.
* @param pages view names for the pages
*/
public final void setPages(String[] pages) {
if (pages == null || pages.length == 0) {
throw new IllegalArgumentException("No wizard pages defined");
}
this.pages = pages;
}
위저드 페이지를 세팅하는 메소드이다. 세팅된 페이지는 문자열 배열에 들어가지게 되고 문자열배열의 인덱스번호가 위저드 페이지 번호가 되여진다.
* Set if "dirty back" is allowed, that is, if moving to a former wizard
* page is allowed in case of validation errors for the current page.
* @param allowDirtyBack if "dirty back" is allowed
*/
public final void setAllowDirtyBack(boolean allowDirtyBack) {
this.allowDirtyBack = allowDirtyBack;
}
/**
* Set if "dirty forward" is allowed, that is, if moving to a later wizard
* page is allowed in case of validation errors for the current page.
* @param allowDirtyForward if "dirty forward" is allowed
*/
public final void setAllowDirtyForward(boolean allowDirtyForward) {
this.allowDirtyForward = allowDirtyForward;
}
dirty back와 dirty forward 두가지 속성은 기본 dirty back = true로, dirty forward = false로 설정이 되여져 있는데 그 의미는 현재 머물고 있는 페이지에 validation 오류가 존재할 시 앞 혹은 뒤 페이지로의 이동 허용여부를 세팅한다. dirty back = true로 되여져있으면 현재 페이지에 validation 오류가 있을시 뒷페이지의 이동을 허용한다는 뜻이 되겠다.
2007년 8월 30일 목요일
Spring + DWR 을 이용한 Form Submission처리...
Spring 은 Form Submission을 받으면 Form handler는 새로운 FormBackingObject를 생성하고 폼에 의하여 입력이 되여진 각 Elements들은 Reflection방식으로 적절한 setter메소드의하여 POJO에 세팅이 되여진다. 이러한 바인딩 과정은 모든 input elements에 발생한다.
DWR을 이용한 AJAX Request는 일반적인 Form Submission방식이 아니고 넘기는것은 오로지 FormID 와 관련 데이타뿐이기 때문에 Spring의 FormBackingObject는 자동으로 이렇게 넘겨받은 값들을 바인딩시켜줄수 없다.
2007년 8월 29일 수요일
Spring MVC의 HandlerExceptionResolver 를 사용한 예외 처리
Spring에서 예외 처리하기 위해서는 모두 두가지 방법이 있다.
간단히 설정파일로만 예외처리를 하려면 SimpleMappingExceptionResolver를 사용하면 되겠다.
Spring MVC에서는 쉽게 예외처리와 설정을 하기 위해서 SimpleMappingExceptionResolver를 제공한다. SimpleMappingExceptionResolver을 사용함으로써 컨트롤러나 인터셉터에 산재해 있는 예외 처리에 관련된 설정들을 중앙 집중(centralize)할 수 있게 된다.
매개 Exception마다 지정된 ModelAndView를 할당해 줄수 있고 이런것들은 doResolveException에 의하여 처리되고 매핑된 ModelAndView페이지를 리턴하게 된다.
Spring내에서 커스터마이징된 익셉션을 관리하기 위하여 applicationContext.xml안에 아래와 같이 설정을 해주면 된다.
[code xml] <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <!-- Exception Resolver --> <bean id="exceptionMapping" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="DataNotFoundException">exception/ErrorMessage</prop> </props> </property> <property name="exceptionAttribute" value="exceptionMsg" /> <property name="defaultErrorView" value="Error" /> </bean> </beans> [/code] DataNotFoundException이 발생하게 되면 exception/DataNotFoundException ViewName을 리턴하게 되고 SimpleMappingExceptionResolver에서 viewName에 의거하여 해당 ModelAndView를 리턴하게 된다. view를 찾을 때에는 viewResolver가 역시 사용 된다.
하나 이상의 excpetion을 처리하는 resolver가 등록되어 있는 경우에는 Ordered 인터페이스를 구현해 우선 순위를 정할 수 있다.
위 속성을 제외하고도 SimpleMappingExceptionResolver는 여러가지 유용한 속성들을 노출시키고 있다. 아래에 자주쓰이는 몇몇 속성들에 대하여 설명할가 한다.
mappedHandlerClasses : 특정된 맵 핸들러클래스를 세팅해줄수 있다.
defaultErrorView : 지정된 예외가 아닌 예외일때 기본적으로 포워딩해줄 view페이지를 세팅할수있다.
defaultStatusCode : 예외가 떴을대 HTTP 상태코드를 세팅해줄수가 있다. 단 이 세팅은 Top - Level Request에만 유효하다.
exceptionAttribute : 예외가 노출시킬 기본 모델 속성을 세팅할수 있다. 기본적으로 exception으로 설정이 되여있으나 경우에 따라 변경할수 있다. 만약 이 속성에 값을 세팅하지 않으면 기본적으로 view페이지에서 ${exception.message}를 통하여 예외메세지를 받을수 있다.
아래에 Exception의 상속을 구조를 알아보겠다.
ExceptionDetail 이 만약 ExceptionBase를 상속받은 상태에서 ExceptionDetail 이 발생하였고 또한 설정파일이 아래와 같이 설정이 되여져 있는 상태라면
[code xml] <property name="exceptionMappings"> <props> <prop key="ExceptionBase">basePage</prop> </props> </property> [/code] basePage가 viewName으로 리턴을 받게 된다.
프로그래밍적 즉 하드코딩방식으로 예외처리를 할려면 HandlerExceptionResolver 인터페이스를 직접 상속받어가지고 구현하여야만 한다.
[code java] import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.ModelAndView; public class BaseExceptionResolver implements HandlerExceptionResolver { private String view = null; public void setView(String view) { this.view = view; } public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object obj, Exception exception) { request.setAttribute("exception",exception); return new ModelAndView(view); } } [/code] 또한 bean 은 아래와 같이 설정해주어야 한다.
[code xml] <bean id="exceptionResolver" class="BaseExceptionResolver"> <property name="view" value="error"/> </bean> [/code] 윗방법을 쓰는 원인은 Request로 Exception을 넘기기 위해서이다.
2007년 7월 16일 월요일
Spring MVC를 이용하기 위한 Web.xml에 대한 설정
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<!-- Servlet configuration for Spring -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/action-servlet.xml
</param-value>
</context-param>
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Servlet Mapping -->
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
Spring MVC에서 요청에 대한 생명주기
- Spring MVC 또한 클라이언트의 요청이 처음으로 진입되는 지점은 DispatcherServlet이다.
- 클라이언트로부터 요청이 들어오면 DispatcherServlet은 빈 설정 파일에 정의되여 있는 HandlerMapping을 이용하여 요청 URL에 해당하는 Controller 객체를 얻게 된다.
- DispatcherServlet은 HandlerMapping으로부터 Controller를 얻게 되면 요청에 대한 모든 작업을 Controller에게 위임하게 된다.
- Controller는 비즈니스 계층과의 통신을 완료한 다음 비즈니스 계층에서 전달된 모델 데이타와 클라이언트에게 보여줄 뷰화면에 대한 정보를 ModelAndView 클래스에 담아서 DispatcherServlet에 반환하게 된다.
- DispatcherServlet은 View객체를 이용하여 클라이언트에 화면을 출력하게 된다.
- 만약 ModelAndView에 저장되여 있는 View정보가 논리적인 View이름일 경우에는 빈 설정 파일에 정의되어 있는 ViewResolver 클래스를 이용하여 클라이언트에게 출력할 View객체를 얻게 된다.
2007년 2월 27일 화요일
Spring과 Timer 사이의 연동으로 인한 스케쥴링
스케쥴링을 하기 위하여서는 아래 몇가지 개념부터 먼저 잡고 넘어가야한다.
job : 이것은 독립적인 작업단위로서 job은 지정된 단위간격을 주기로 실행이 되여진다.
trigger : job의 실행을 하기위한 조건을 명시한다. 이런 조건은 단순히 고정된 시간으로 구성이 되여질수 도 있고 아니면 복잡한 데이타로 구성이 되여질수도 있다.
scheduler : trigger의 집합으로써 직책은 전체 스케쥴링 시스템을 관리하는것이다.
Spring은 여러가지 보조적 클래스를 이용하여 Timer와 연동하여 사용되여진다.
ScheduledTimerTask와 TimerTask가 그 가장 대표적인 보조클래스이다.
또한 TimerFactoryBean을 통하여 Spring은 자동적으로 지정된 trigger한테 새로운 공유된 Timer 인스턴스를 생성해주고 Timer는 이런 Trigger 를 이용하여 해당 job을 실행해준다.
ApplicationContextTimer.xml
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- 주입시킬 클래스를 선언적 방식으로 명시하였다. -->
<bean id="generatorJob"
class="com.xxx.nnserp.spring.SmsTransferLegacy">
</bean>
<!-- MethodInvokingTimerTaskFactoryBean을 사용하여
generatorJob의 동적 프록시를 생성하였으며 TimerTask의 특성을 가지게 하였다. -->
<bean id="generatorJobProxy"
class="org.springframework.scheduling.timer.
MethodInvokingTimerTaskFactoryBean">
<property name="targetObject">
<ref local="generatorJob"/>
</property>
<property name="targetMethod">
<value>send</value>
</property>
<property name="arguments">
<value>xxx</value>
</property>
</bean>
<!-- 실제 타이머태스크가 작동할 시간단위를 설정해준다. -->
<bean id="repeatingTrigger"
class="org.springframework.scheduling.timer.ScheduledTimerTask">
<!-- 시동후 20초후 작업을 실행한다. -->
<property name="delay">
<value>20000</value>
</property>
<!-- 매 5초마다 작업을 실행한다. -->
<property name="period">
<value>5000</value>
</property>
<!-- 위에서 선언한 generatorJobProxy를 timerTask에 주입시킨다. -->
<property name="timerTask">
<ref local="generatorJobProxy" />
</property>
</bean>
<!-- 스케쥴러속성에 타임태스크와 반복설정관련 트리거를 추가해준다. -->
<bean id="scheduler"
class="org.springframework.scheduling.timer.TimerFactoryBean">
<property name="scheduledTimerTasks">
<list>
<ref local="repeatingTrigger" />
</list>
</property>
</bean>
</beans>
ApplicationContextTimer.xml 는 Spring의 ApplicationContext에 대한 설정파일로서 이 예제에서는 실제 타이머 어떻게 작동할것인지에 대한 룰들을 정의하고 또한 어느 클래스에 대하여 스케쥴링을 할것인지를 설정해준다.
SmsTransferLegacy.java
public void send(String args)
{
System.out.println(LibDatetime.getTimeString() + " 시각에 " + args +
"에 SMS 발송!");
}
}
SmsTransferLegacy.java 클래스는 사실상 주기적으로 실행이 되여져야 할 클래스로서 이 예제에서는 단순히 실행이 되여질때마다 타임스템프를 출력시키는것으로 구현했다.