티스토리 뷰
KH 104일차 - mybatis ( 동적 SQL 처리 ) / 쿼츠 (quartz) - 스케줄링 (*****)
monimoni 2022. 7. 26. 15:341. 쿼츠 기반의 Job Sceduling
- 1 ) `Job` interface : 스케줄링되어 실행될 task의 규격
- -> Job 인터페이스를 상속 받는 구현 클래스 생성 ( jobA, JobB, SimpleJob )
- + 스케쥴링을 하기 전에 Task를 Job 규격에 맞게 생성해야 한다.
- + 이는 스케쥴링의 대상(Target)이 된다.
- 2 ) ‘JobDetail’ Interface
- -> `JobBuilder`를 이용하여 구현객체 생성
- + 1 )의 Job에 대한 상세정보를 규격에 맞게 생성한다.
- + 1 )의 Job 실행에 필요한 데이터도 Map의 형태로 설정할 수 있다.
- + 1 )의 Job에 대한 name과 Group name도 설정할 수 있다.
- 3 ) ‘Trigger’ Interface : 스케줄링에 대한 정보
- -> `TriggerBuilder`를 이용하여 구현객체 생성
- + 위 1 )의 Job을 어떻게 실행시킬지 스케줄링에 대한 정보를 설정한다.
- + 예 : 매 1초마다 수행, 매 1시간마다 수행 …
- + Detail과 다르게 재사용이 가능하다.
- 4 ) ‘Scheduler’ interface : 실제 스케쥴된대로 Job을 수행시키는 서버
- -> `StdSchedulerFactory` 클래스를 이용하여 구현객체 생성
- + Job을 이 서버에 등록하기 위해서는 JobDetail과 Trigger가 필요하다. (**)
- 5 ) ListenerManager` interface
- + 4 )의 scheduler의 이벤트를 모니터링하고, 적절한 CallBack마다 무엇을 수행할 수 있는 리스너 객체를 만들어 등록하는 곳
- + 예 : 시작할 때, 오류가 났을 때 등등 로그를 찍게 할 수 있다.
[ 1. 동적 SQL 처리 ] (***)
[ 1 - 1. mapper에 sql문 준비 ]
<!-- 4. 게시판 검색어 조건에 맞게, 특정 게시글 번호로 검색해서 반환 1 ( 안전하지 않음 ) -->
<select id="findBoardByBno" resultType="org.zerock.myapp.domain.BoardVO">
SELECT bno, title, content, writer, insert_ts, update_ts
FROM tbl_board
WHERE
<if test="bno != null">
bno = #{bno}
</if>
</select>
<!-- 5. 게시판 검색어 조건에 맞게, 특정 제목으로 검색해서 반환 2 (****) -->
<select id="findBoardByTitle" resultType="org.zerock.myapp.domain.BoardVO">
SELECT bno, title, content, writer, insert_ts, update_ts
FROM tbl_board
<where>
<if test="title != null">
title LIKE '%'||#{title}||'%'
<!-- 와일드 카드로 title로 검색 -->
</if>
</where>
</select>
<!-- 5 - 2. 게시판 검색어 조건에 맞게, 특정 제목으로 검색해서 반환 2 (****) -->
<select id="findBoardByTitle2" resultType="org.zerock.myapp.domain.BoardVO">
SELECT bno, title, content, writer, insert_ts, update_ts
FROM tbl_board
<where>
<if test="title != null">
title LIKE #{title}
</if>
</where>
</select>
<!-- 6. 게시판 검색어 조건에 맞게, 특정 작가로 검색해서 반환 3 -->
<select id="findBoardByWriter" resultType="org.zerock.myapp.domain.BoardVO">
SELECT bno, title, content, writer, insert_ts, update_ts
FROM tbl_board
<trim prefix="WHERE" prefixOverrides="AND | OR">
<if test="writer != null">
writer LIKE '%'||#{witer}||'%'
<!-- 와일드 카드로 writer 검색 -->
</if>
</trim>
</select>
<!-- 7. 게시판 검색어 조건에 맞게, 특정 게시글 번호와 제목을 검색해서 반환 4 -->
<select id="findBoardByBnoAndtitle" resultType="org.zerock.myapp.domain.BoardVO">
SELECT bno, title, content, writer, insert_ts, update_ts
FROM tbl_board
<!-- 다중 조건식( 체크 조건이 여러개인 경우 )의 처리 -->
<!-- prefix는 실행될 쿼리의 <trim> 태그 안에 쿼리 가장 앞에 붙여준다. -->
<!-- prefixOverrides는 조건식이 2개 이상일 때 사용한다. -->
<!-- prefixOverrides는 실행될 쿼리의 <trim> 문 안에 쿼리 가장 앞에 해당하는 문자들이 있으면 자동으로 지워준다. -->
<trim prefix="WHERE" prefixOverrides="AND | OR">
<if test="bno != null">
bno = #{bno}
</if>
<if test="title != null">
AND title LIKE '%'||#{title}||'%'
</if>
</trim>
</select>
<!-- 8. 게시판 검색어 조건에 맞게, 특정 게시글 번호 또는 제목을 검색해서 반환 5 (******) -->
<select id="findBoardByBnoOrWriter" resultType="org.zerock.myapp.domain.BoardVO">
SELECT bno, title, content, writer, insert_ts, update_ts
FROM tbl_board
<!-- switch 문 -->
<where>
<choose>
<!-- when은 하나만 실행이 된다. -->
<!-- switch와 동일! -->
<when test="bno != null">
bno = #{bno}
</when>
<when test="title != null">
OR title LIKE '%'||#{title}||'%'
</when>
<!-- 그렇지 않으면 컨탠츠 내용내에서 검색하라 -->
<!-- otherwise는 필수사항이 아닌 선택사항이다. -->
<otherwise>
content LIKE %||#{content}||'%'
</otherwise>
</choose>
</where>
</select>
<!-- 9. 게시판 검색어 조건에 맞게, 특정 게시글 번호를 검색해서 반환 ( 검색어가 여러개 ) 6 (******) -->
<select id="findBoardsBySomeBnos" resultType="org.zerock.myapp.domain.BoardVO">
SELECT bno, title, content, writer, insert_ts, update_ts
FROM tbl_board
<where>
<!-- ( bno1, bno2, bno3 ... ) -->
<!-- item은 list의 원소를 bno로 꺼내겠다는 의미이다. -->
<!-- collection="list"은 타입이기에 이름을 바꾸면 안된다. -->
<foreach collection="list" item="bno" index="index" open="bno IN (" close=")" separator=",">
#{bno}
</foreach>
</where>
</select>
[ 1 - 2. 동적 sql 실행 ]
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.Timeout;
import org.zerock.myapp.domain.BoardVO;
import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;
@Log4j2
@NoArgsConstructor
@TestInstance(Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class DynamicSQLWithConfigXmlTests {
private SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
private SqlSessionFactory sqlSessionFactory;
// =========================================================================================
@BeforeAll
void beforeAll() throws IOException {
log.debug("beforeAll() invoked.");
String mybatisConfigXml = "mybatis-config.xml";
InputStream is = Resources.getResourceAsStream(mybatisConfigXml);
try( is; ){
this.sqlSessionFactory = builder.build(is);
Objects.requireNonNull(this.sqlSessionFactory);
log.info( "\t + sqlSessionFactory : {}", this.sqlSessionFactory );
} // try - with - resources
} // beforeAll()
// =========================================================================================
// <!-- 1. 게시판 검색어 조건에 맞게, 특정 게시글 번호로 검색해서 반환 1 ( 안전하지 않음 ) -->
// <select id="findBoardByBno" resultType="org.zerock.myapp.domain.BoardVO">
// SELECT bno, title, content, writer, insert_ts, update_ts
// FROM tbl_board
// WHERE
//
// <if test="bno != null">
// bno = #{bno}
// </if>
// </select>
// =========================================================================================
// @Disabled
@Test
@Order(1)
@DisplayName("1. findBoardByBno")
@Timeout(value=5000, unit=TimeUnit.MILLISECONDS)
public void findBoardByBno() {
log.info("findBoardByBno() invoked.");
SqlSession sqlSession = this.sqlSessionFactory.openSession();
log.info("\t + 1. sqlSession : {}", sqlSession);
try ( sqlSession; ){
Integer bno = 172;
String namespace = "BoardMapper";
String sqlId = "findBoardByBno";
BoardVO board = sqlSession.<BoardVO>selectOne(namespace+"."+sqlId, bno);
Objects.requireNonNull(board);
log.info("\t + 1. board : {}", board);
// ============================================================================
// List도 가능
// List <BoardVO> boards = sqlSession.<BoardVO>selectList(namespace+"."+sqlId, bno);
// Objects.requireNonNull(boards);
// boards.forEach(log::info);
// ============================================================================
} // try - with - resources
} // selectAllBoards
// =========================================================================================
// <!-- 2. 게시판 검색어 조건에 맞게, 특정 제목으로 검색해서 반환 2 (*****) -->
// <select id="findBoardByTitle" resultType="org.zerock.myapp.domain.BoardVO">
//
// SELECT bno, title, content, writer, insert_ts, update_ts
// FROM tbl_board
//
// <where>
//
// <if test="title != null">
// title LIKE '%'||#{title}||'%'
// <!-- 와일드 카드로 title로 검색 -->
// </if>
//
// </where>
//
// </select>
// =========================================================================================
// @Disabled
@Test
@Order(2)
@DisplayName("2. findBoardByTitle")
@Timeout(value = 5000, unit = TimeUnit.MILLISECONDS)
public void findBoardByTitle() {
log.info("findBoardByTitle() invoked.");
SqlSession sqlSession = this.sqlSessionFactory.openSession();
log.info("\t + 2. sqlSession : {}", sqlSession);
try ( sqlSession; ) {
// '%'||#{title}||'%'로 제목에 7이 들어간 것을 출력하게 지정
String title = "7";
// String title = null;
// null을 넣으면 where절이 만들어지지 않기에
// SELECT bno, title, content, writer, insert_ts, update_ts FROM tbl_board만 수행되어
// 모든 칼럼이 출력된다.
String namesapce = "BoardMapper";
String sqlId = "findBoardByTitle";
List<BoardVO> boards = sqlSession.<BoardVO>selectList(namesapce + "." + sqlId, title);
Objects.requireNonNull(boards);
boards.forEach(log::info);
} // try - with - resources
} // findBoardByTitle
// =========================================================================================
// <!-- 5 - 2. 게시판 검색어 조건에 맞게, 특정 제목으로 검색해서 반환 2 (****) -->
// <select id="findBoardByTitle2" resultType="org.zerock.myapp.domain.BoardVO">
// SELECT bno, title, content, writer, insert_ts, update_ts
// FROM tbl_board
//
// <where>
//
// <if test="title != null">
// title LIKE #{title}
// </if>
//
// </where>
//
// </select>
// =========================================================================================
// @Disabled
@Test
@Order(3)
@DisplayName("3. findBoardByTitle2")
@Timeout(value = 5000, unit = TimeUnit.MILLISECONDS)
public void findBoardByTitle2() {
log.info("findBoardByTitle2() invoked.");
SqlSession sqlSession = this.sqlSessionFactory.openSession();
log.info("\t + 3. sqlSession : {}", sqlSession);
try ( sqlSession; ) {
// 정확히 제목이 TITLE_7인 칼럼을 출력하게 지정
// String title에 7을 넣으면, 제목이 7인 칼럼은 없기에 출력되지 않는다.
String title = "TITLE_7";
// String title = null;
// null을 넣으면 where절이 만들어지지 않기에
// SELECT bno, title, content, writer, insert_ts, update_ts FROM tbl_board만 수행되어
// 모든 칼럼이 출력된다.
String namesapce = "BoardMapper";
String sqlId = "findBoardByTitle2";
List<BoardVO> boards = sqlSession.<BoardVO>selectList(namesapce + "." + sqlId, title);
Objects.requireNonNull(boards);
boards.forEach(log::info);
} // try - with - resources
} // findBoardByTitle2
// =========================================================================================
// <!-- 6. 게시판 검색어 조건에 맞게, 특정 작가로 검색해서 반환 3 -->
// <select id="findBoardByWriter" resultType="org.zerock.myapp.domain.BoardVO">
// SELECT bno, title, content, writer, insert_ts, update_ts
// FROM tbl_board
//
// <trim prefix="WHERE" prefixOverrides="AND | OR">
//
// <if test="writer != null">
// writer LIKE '%'||#{witer}||'%'
// <!-- 와일드 카드로 writer 검색 -->
// </if>
//
// </trim>
// </select>
// =========================================================================================
// @Disabled
@Test
@Order(4)
@DisplayName("4. findBoardByWriter")
@Timeout(value = 5000, unit = TimeUnit.MILLISECONDS)
public void findBoardByWriter() {
log.info("findBoardByWriter() invoked.");
SqlSession sqlSession = this.sqlSessionFactory.openSession();
log.info("\t + 4. sqlSession : {}", sqlSession);
try ( sqlSession; ) {
// 작가 이름 중에 17이 포함되어있는 칼럼을 출력
String writer = "17";
String namesapce = "BoardMapper";
String sqlId = "findBoardByWriter";
List<BoardVO> boards = sqlSession.<BoardVO>selectList(namesapce + "." + sqlId, writer);
Objects.requireNonNull(boards);
boards.forEach(log::info);
} // try - with - resources
} // findBoardByWriter
// =========================================================================================
// <!-- 7. 게시판 검색어 조건에 맞게, 특정 게시글 번호와 제목을 검색해서 반환 4 -->
// <select id="findBoardByBnoAndWriter" resultType="org.zerock.myapp.domain.BoardVO">
// SELECT bno, title, content, writer, insert_ts, update_ts
// FROM tbl_board
//
// <!-- 다중 조건식( 체크 조건이 여러개인 경우 )의 처리 -->
// <!-- prefix는 실행될 쿼리의 <trim> 태그 안에 쿼리 가장 앞에 붙여준다. -->
// <!-- prefixOverrides는 조건식이 2개 이상일 때 사용한다. -->
// <!-- prefixOverrides는 실행될 쿼리의 <trim> 문 안에 쿼리 가장 앞에 해당하는 문자들이 있으면 자동으로 지워준다. -->
// <trim prefix="WHERE" prefixOverrides="AND | OR">
//
// <if test="bno != null">
// bno = #{bno}
// </if>
//
// <if test="title != null">
// AND title LIKE '%'||#{title}||'%'
// </if>
//
// </trim>
//
// </select>
// =========================================================================================
// @Disabled
@Test
@Order(5)
@DisplayName("5. findBoardByBnoAndtitle")
@Timeout(value = 5000, unit = TimeUnit.MILLISECONDS)
public void findBoardByBnoAndtitle() {
log.info("findBoardByBnoAndtitle() invoked.");
SqlSession sqlSession = this.sqlSessionFactory.openSession();
log.info("\t + 5. sqlSession : {}", sqlSession);
try ( sqlSession; ) {
Integer bno = 33;
String title = "17";
String namesapce = "BoardMapper";
String sqlId = "findBoardByBnoAndtitle";
Map<String, Object> params = new HashMap<>();
params.put("bno", bno);
params.put("title", title);
List<BoardVO> boards = sqlSession.<BoardVO>selectList(namesapce + "." + sqlId, params);
Objects.requireNonNull(boards);
boards.forEach(log::info);
} // try - with - resources
} // findBoardByBnoAndWriter
// =========================================================================================
// <!-- 8. 게시판 검색어 조건에 맞게, 특정 게시글 번호 또는 제목을 검색해서 반환 5 (*******) -->
// <select id="findBoardByBnoOrWriter" resultType="org.zerock.myapp.domain.BoardVO">
// SELECT bno, title, content, writer, insert_ts, update_ts
// FROM tbl_board
//
// <!-- switch 문 -->
// <where>
//
// <choose>
//
// <when test="bno != null">
// bno = #{bno}
// </when>
//
// <when test="title != null">
// OR title LIKE '%'||#{title}||'%'
// </when>
//
// <!-- 그렇지 않으면 컨탠츠 내용내에서 검색하라 -->
// <!-- otherwise는 필수사항이 아닌 선택사항이다. -->
// <otherwise>
// content LIKE %||#{content}||'%'
// </otherwise>
//
// </choose>
//
// </where>
//
// </select>
// =========================================================================================
// @Disabled
@Test
@Order(6)
@DisplayName("6. findBoardByBnoOrWriter")
@Timeout(value = 5000, unit = TimeUnit.MILLISECONDS)
public void findBoardByBnoOrWriter() {
log.info("findBoardByBnoOrWriter() invoked.");
SqlSession sqlSession = this.sqlSessionFactory.openSession();
log.info("\t + 6. sqlSession : {}", sqlSession);
try ( sqlSession; ) {
Integer bno = 33;
String title = "17";
String namesapce = "BoardMapper";
String sqlId = "findBoardByBnoOrWriter";
Map<String, Object> params = new HashMap<>();
params.put("bno", bno);
params.put("title", title);
// case - when의 경우에는 swith문과 동일하게
// 같은 조건을 달성하는 when이 많을지라도 하나의 when만 실행시킨다.
// 만약 title만 작성되어, 2번째 when이 실행되면 앞의 OR로 인해 문제가 발생한다고 걱정할 수 있지만,
// 마이 바티스가 자동으로 지워주기에 괜찮은 부분이다.
List<BoardVO> boards = sqlSession.<BoardVO>selectList(namesapce + "." + sqlId, params);
Objects.requireNonNull(boards);
boards.forEach(log::info);
} // try - with - resources
} // findBoardByBnoOrWriter
// =========================================================================================
// <!-- 9. 게시판 검색어 조건에 맞게, 특정 게시글 번호를 검색해서 반환 ( 검색어가 여러개 ) 6 (******) -->
// <select id="findBoardsBySomeBnos" resultType="org.zerock.myapp.domain.BoardVO">
// SELECT bno, title, content, writer, insert_ts, update_ts
// FROM tbl_board
//
// <where>
//
// bno IN
//
// <!-- ( bno1, bno2, bno3 ... ) -->
// <!-- item은 list의 원소를 bno로 꺼내겠다는 의미이다. -->
// <foreach collection="list" item="bno" index="index" open="(" close=")" separator=",">
// #{bno}
// </foreach>
//
// </where>
// </select>
// =========================================================================================
// @Disabled
@Test
@Order(7)
@DisplayName("7. findBoardsBySomeBnos")
@Timeout(value = 5000, unit = TimeUnit.MILLISECONDS)
public void findBoardsBySomeBnos() {
log.info("findBoardsBySomeBnos() invoked.");
SqlSession sqlSession = this.sqlSessionFactory.openSession();
log.info("\t + 7. sqlSession : {}", sqlSession);
try ( sqlSession; ) {
List<Integer> bnoList = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
log.info("\t + 7. bnoList : {}", bnoList);
String namesapce = "BoardMapper";
String sqlId = "findBoardsBySomeBnos";
List<BoardVO> boards = sqlSession.<BoardVO>selectList(namesapce + "." + sqlId, bnoList);
Objects.requireNonNull(boards);
boards.forEach(log::info);
} // try - with - resources
} // findBoardsBySomeBnos
// =========================================================================================
} // end class
[ 2. 쿼츠 - pom.xml 파일 설정 ]
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.zerock</groupId>
<artifactId>studyquartz</artifactId>
<version>1.0.0-BUILD-SNAPSHOT</version>
<packaging>jar</packaging>
<name>studyquartz</name>
<url>http://studyquartz.example.com</url>
<description>Learing the Quartz Job Scheduler</description>
<properties>
<java-version>11</java-version>
<!-- <java-home>${env.JAVA_HOME}</java-home> -->
<!-- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target> -->
<org.apache.logging.log4j-version>2.17.2</org.apache.logging.log4j-version>
</properties>
<dependencies>
<!-- =============== Logging =============== -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${org.apache.logging.log4j-version}</version>
</dependency>
<!-- For Spring framework, HikariCP, DriverSpy logging -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>${org.apache.logging.log4j-version}</version>
</dependency>
<!-- =============== Testing =============== -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
<!-- =============== Misc =============== -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.10</version>
<configuration>
<downloadSources>true</downloadSources>
<downloadJavadocs>false</downloadJavadocs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.0</version>
<configuration>
<release>${java-version}</release>
</configuration>
</plugin>
</plugins>
</build>
</project>
[ 3. 쿼츠 - 스케줄 ] (****)
[ 3 - 1. Job 생성 ]
[ JobA ]
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;
@Log4j2
@NoArgsConstructor
public class JobA implements Job {
@Override
public void execute(JobExecutionContext ctx) throws JobExecutionException {
log.trace("execute({}) invoked.", ctx);
try {
log.info("--------------- JobA invoked. ---------------");
} catch ( Exception e ) {
throw new JobExecutionException (e);
} // try - catch
} // execute
} // JobA
[ JobB ]
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;
@Log4j2
@NoArgsConstructor
public class JobB implements Job {
@Override
public void execute(JobExecutionContext ctx) throws JobExecutionException {
log.trace("execute({}) invoked.", ctx);
try {
log.info("--------------- JobB invoked. ---------------");
// JobDetail에서 넘겨준 데이터를 작업 처리에 사용
JobDataMap map = ctx.getJobDetail().getJobDataMap();
// JobDetail에서 넘겨준 데이터에서 Value 빼오기
String key1 = (String)map.get("KEY_1");
String key2 = map.getString("KEY_2");
String key3 = map.getString("KEY_3");
log.info("\t + Key1 : {}, Key2 :{}, Key3 : {}", key1, key2, key3);
} catch ( Exception e ) {
throw new JobExecutionException (e);
} // try - catch
} // execute
} // JobB
[ 3 - 2. Job 스케줄링 및 실행 ] (*****)
import org.quartz.DailyTimeIntervalScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.ListenerManager;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerListener;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.DateBuilder.IntervalUnit;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.calendar.DailyCalendar;
import org.zerock.myapp.job.JobA;
import org.zerock.myapp.job.JobB;
import org.zerock.myapp.listener.SchedulerListenerlmpl;
import lombok.extern.log4j.Log4j2;
@Log4j2
public class SchedulingServer {
// 우리가 생성한 3개의 Job을 스케줄링해서 실행시킨다.
public static void main(String[] args) {
log.trace("SchedulingServer invoked.");
try {
// ================================================
// 1단계 : 'Scheduler' 인터페이스의 구현객체 획득
// ================================================
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
log.info("\t + 1. scheduler : {}", scheduler);
// ================================================
// 2단계 : JobA를 위한 'JobDetail' 인터페이스의 구현객체 생성
// ================================================
// 2 - 1. 쿼츠 JOB Detail to be scheduled
// + JobDetail은 JobA만을 위한 것이기에, 재사용은 불가능하다.
JobDetail jobADetail =
JobBuilder.newJob(JobA.class).
withIdentity("JobA", "GROUP1"). // withIdentity(Job name, Job 소속 group) Job의 이름과 Job의 소속이름을 생성
withDescription("JOB A"). // withDescription는 이에 대한 설명을 작성할 수 있다.
usingJobData("KEY1", "VALUE1").
usingJobData("KEY2", "VALUE2").
build(); // .build는 JobDetail 객체를 만들어 준다.
// 2 - 2. 트리거는 잡 스케쥴을 어떻게 수행시킬지 정해준다. ( 스케줄링 정보 )
// + 트리거는 JobA를 위한 트리거가 아니기에, 재사용이 가능하다.
// + Job Scheduling registered to the Quartz Scheduler
Trigger jobATrigger =
TriggerBuilder.
newTrigger(). // 새로운 트리거 생성
withIdentity("JobA Trigger", "GROUP1"). // 트리거의 이름 생성
withDescription("Scheduling for JobA"). // 트리거 설명
withPriority(15). // 트리거의 우선순위
startNow(). // 지금 시작해라
withSchedule( SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1).repeatForever() ). // 반복되는 시간과 횟수를 지정
build();
// + 이러한 트리거를 통해 구동 시에는 1초마다 무한으로 반복해서 수행된다.
// + repeatForever()대신 다른 것을 넣어 제한적인 횟수만 반복되게 할 수도 있다.
// + 횟수는 시작하는 횟수를 제외한 횟수로 10을 지정했을 시에는 처음 시작 1번 + 반복횟수 10번이 찍힌다.
// ================================================
// 2단계 : JobB를 위한 'JobDetail' & jobTrigger 인터페이스의 구현객체 생성
// ================================================
// jobB를 위한 상세 정보
JobDetail jobBDetail =
JobBuilder.
newJob(JobB.class).
withIdentity(JobKey.jobKey("JobB", "GROUP1")).
withDescription("Job Description for JobB").
usingJobData("KEY_1","VALUE_1").
usingJobData("KEY_2","VALUE_2").
usingJobData("KEY_3","VALUE_3").
build();
// jobB 트리거
Trigger jobBTrigger =
TriggerBuilder.
newTrigger().
withIdentity(TriggerKey.triggerKey("JobB Trigger", "GROUP1")).
withDescription("Scheduling for JobB").
startNow(). // 어느때 시작할까? (***)
withSchedule( // 시작이후에 어떻게 재기동할까? (****)
DailyTimeIntervalScheduleBuilder.
dailyTimeIntervalSchedule().
withInterval(3, IntervalUnit.SECOND). // 3초 간격으로 ( 여기에서는 밀리세컨드가 불가능 )
withRepeatCount(3) // 반복 횟수
).
build();
// ================================================
// 3단계 : Scheduler에 JobA / jobADetail / jobATrigger 등록
// + Scheduler를 이용하여 지정된 Job을 지정한 대로 schedule 등록
// + JobA는 jobADetail이 가지고 있다.
// ================================================
scheduler.scheduleJob(jobADetail , jobATrigger);
scheduler.scheduleJob(jobBDetail , jobBTrigger);
// ================================================
// 4단계 : Listener 객체를 생성 및 등록하여,
// + scheduler / Job / Trigger 이벤트를 모니터링할 수 있다.
// + SchedulerListener을 implement하는 리스너를 생성해야 한다. (***)
// ================================================
ListenerManager lm = scheduler.getListenerManager();
lm.addSchedulerListener(new SchedulerListenerlmpl());
// ================================================
// 5단계 : 3단계에 등록한 jobADetail / jobATrigger대로 Job을 수행
// ================================================
scheduler.start();
} catch (SchedulerException e) {
// 발생한 예외를 출력하고 정상 종료를 시킨다.
e.printStackTrace();
} finally {
log.info("Done!");
} // try - catch - finally
} // main
} // end class
[ 4. 실행환경 jar파일로 export하기 ] (****)
[ 4 - 1. 프로젝트 선택 -> 오른쪽 클릭 -> Export 클릭 -> Runnable JAR file 선택 ]
[ 4 - 2. 1 ) jar파일 만들 프로젝트 선택 / 2 ) jar파일 저장할 경로 선택 / 저장할 타입 선택 ]
[ 4 - 3. 파워쉘에서 확인 ]
- PS C:\jar저장위치> java -jar .\jar파일명.jar
'KH 정보교육원 [ Java ]' 카테고리의 다른 글
KH 106일차 - Spring ( 의존성 주입(DI) ) (*****) (0) | 2022.07.28 |
---|---|
KH 105일차 - Spring 설치 및 프로젝트 생성 (*****) (0) | 2022.07.27 |
KH 103일차 - myBatis마이바틱스 3 ( 검색조건 설정 / 히카리CP ) (*****) (0) | 2022.07.25 |
KH 102일차 - myBatis ( 마이 바틱스 ) (*****) (0) | 2022.07.22 |
KH 101일차 - mybatis ( 마이 바틱스 ) (*****) (0) | 2022.07.21 |