quartz 통합 spring 클 러 스 터 배치
quartz 단일 노드 가 업무 의 수 요 를 만족 시 키 지 못 하기 때문에 그 다음 에 우 리 는 단일 노드 를 바탕 으로 클 러 스 터 배 치 를 실시 했다.
이전 정시 작업 정 보 를 jobs. xml 설정 파일 에 넣 고 데이터베이스 에 옮 깁 니 다.
1. 새 데이터베이스 시트
CREATE TABLE qrtz_job_details
(
SCHED_NAME VARCHAR2(120) NOT NULL,
JOB_NAME VARCHAR2(200) NOT NULL,
JOB_GROUP VARCHAR2(200) NOT NULL,
DESCRIPTION VARCHAR2(250) NULL,
JOB_CLASS_NAME VARCHAR2(250) NOT NULL,
IS_DURABLE VARCHAR2(1) NOT NULL,
IS_NONCONCURRENT VARCHAR2(1) NOT NULL,
IS_UPDATE_DATA VARCHAR2(1) NOT NULL,
REQUESTS_RECOVERY VARCHAR2(1) NOT NULL,
JOB_DATA BLOB NULL,
CONSTRAINT QRTZ_JOB_DETAILS_PK PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
);
CREATE TABLE qrtz_triggers
(
SCHED_NAME VARCHAR2(120) NOT NULL,
TRIGGER_NAME VARCHAR2(200) NOT NULL,
TRIGGER_GROUP VARCHAR2(200) NOT NULL,
JOB_NAME VARCHAR2(200) NOT NULL,
JOB_GROUP VARCHAR2(200) NOT NULL,
DESCRIPTION VARCHAR2(250) NULL,
NEXT_FIRE_TIME NUMBER(13) NULL,
PREV_FIRE_TIME NUMBER(13) NULL,
PRIORITY NUMBER(13) NULL,
TRIGGER_STATE VARCHAR2(16) NOT NULL,
TRIGGER_TYPE VARCHAR2(8) NOT NULL,
START_TIME NUMBER(13) NOT NULL,
END_TIME NUMBER(13) NULL,
CALENDAR_NAME VARCHAR2(200) NULL,
MISFIRE_INSTR NUMBER(2) NULL,
JOB_DATA BLOB NULL,
CONSTRAINT QRTZ_TRIGGERS_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
CONSTRAINT QRTZ_TRIGGER_TO_JOBS_FK FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)
);
CREATE TABLE qrtz_simple_triggers
(
SCHED_NAME VARCHAR2(120) NOT NULL,
TRIGGER_NAME VARCHAR2(200) NOT NULL,
TRIGGER_GROUP VARCHAR2(200) NOT NULL,
REPEAT_COUNT NUMBER(7) NOT NULL,
REPEAT_INTERVAL NUMBER(12) NOT NULL,
TIMES_TRIGGERED NUMBER(10) NOT NULL,
CONSTRAINT QRTZ_SIMPLE_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
CONSTRAINT QRTZ_SIMPLE_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE qrtz_cron_triggers
(
SCHED_NAME VARCHAR2(120) NOT NULL,
TRIGGER_NAME VARCHAR2(200) NOT NULL,
TRIGGER_GROUP VARCHAR2(200) NOT NULL,
CRON_EXPRESSION VARCHAR2(120) NOT NULL,
TIME_ZONE_ID VARCHAR2(80),
CONSTRAINT QRTZ_CRON_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
CONSTRAINT QRTZ_CRON_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE qrtz_simprop_triggers
(
SCHED_NAME VARCHAR2(120) NOT NULL,
TRIGGER_NAME VARCHAR2(200) NOT NULL,
TRIGGER_GROUP VARCHAR2(200) NOT NULL,
STR_PROP_1 VARCHAR2(512) NULL,
STR_PROP_2 VARCHAR2(512) NULL,
STR_PROP_3 VARCHAR2(512) NULL,
INT_PROP_1 NUMBER(10) NULL,
INT_PROP_2 NUMBER(10) NULL,
LONG_PROP_1 NUMBER(13) NULL,
LONG_PROP_2 NUMBER(13) NULL,
DEC_PROP_1 NUMERIC(13,4) NULL,
DEC_PROP_2 NUMERIC(13,4) NULL,
BOOL_PROP_1 VARCHAR2(1) NULL,
BOOL_PROP_2 VARCHAR2(1) NULL,
CONSTRAINT QRTZ_SIMPROP_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
CONSTRAINT QRTZ_SIMPROP_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE qrtz_blob_triggers
(
SCHED_NAME VARCHAR2(120) NOT NULL,
TRIGGER_NAME VARCHAR2(200) NOT NULL,
TRIGGER_GROUP VARCHAR2(200) NOT NULL,
BLOB_DATA BLOB NULL,
CONSTRAINT QRTZ_BLOB_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
CONSTRAINT QRTZ_BLOB_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE qrtz_calendars
(
SCHED_NAME VARCHAR2(120) NOT NULL,
CALENDAR_NAME VARCHAR2(200) NOT NULL,
CALENDAR BLOB NOT NULL,
CONSTRAINT QRTZ_CALENDARS_PK PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)
);
CREATE TABLE qrtz_paused_trigger_grps
(
SCHED_NAME VARCHAR2(120) NOT NULL,
TRIGGER_GROUP VARCHAR2(200) NOT NULL,
CONSTRAINT QRTZ_PAUSED_TRIG_GRPS_PK PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
);
CREATE TABLE qrtz_fired_triggers
(
SCHED_NAME VARCHAR2(120) NOT NULL,
ENTRY_ID VARCHAR2(95) NOT NULL,
TRIGGER_NAME VARCHAR2(200) NOT NULL,
TRIGGER_GROUP VARCHAR2(200) NOT NULL,
INSTANCE_NAME VARCHAR2(200) NOT NULL,
FIRED_TIME NUMBER(13) NOT NULL,
PRIORITY NUMBER(13) NOT NULL,
STATE VARCHAR2(16) NOT NULL,
JOB_NAME VARCHAR2(200) NULL,
JOB_GROUP VARCHAR2(200) NULL,
IS_NONCONCURRENT VARCHAR2(1) NULL,
REQUESTS_RECOVERY VARCHAR2(1) NULL,
CONSTRAINT QRTZ_FIRED_TRIGGER_PK PRIMARY KEY (SCHED_NAME,ENTRY_ID)
);
CREATE TABLE qrtz_scheduler_state
(
SCHED_NAME VARCHAR2(120) NOT NULL,
INSTANCE_NAME VARCHAR2(200) NOT NULL,
LAST_CHECKIN_TIME NUMBER(13) NOT NULL,
CHECKIN_INTERVAL NUMBER(13) NOT NULL,
CONSTRAINT QRTZ_SCHEDULER_STATE_PK PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)
);
CREATE TABLE qrtz_locks
(
SCHED_NAME VARCHAR2(120) NOT NULL,
LOCK_NAME VARCHAR2(40) NOT NULL,
CONSTRAINT QRTZ_LOCKS_PK PRIMARY KEY (SCHED_NAME,LOCK_NAME)
);
create index idx_qrtz_j_req_recovery on qrtz_job_details(SCHED_NAME,REQUESTS_RECOVERY);
create index idx_qrtz_j_grp on qrtz_job_details(SCHED_NAME,JOB_GROUP);
create index idx_qrtz_t_j on qrtz_triggers(SCHED_NAME,JOB_NAME,JOB_GROUP);
create index idx_qrtz_t_jg on qrtz_triggers(SCHED_NAME,JOB_GROUP);
create index idx_qrtz_t_c on qrtz_triggers(SCHED_NAME,CALENDAR_NAME);
create index idx_qrtz_t_g on qrtz_triggers(SCHED_NAME,TRIGGER_GROUP);
create index idx_qrtz_t_state on qrtz_triggers(SCHED_NAME,TRIGGER_STATE);
create index idx_qrtz_t_n_state on qrtz_triggers(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);
create index idx_qrtz_t_n_g_state on qrtz_triggers(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);
create index idx_qrtz_t_next_fire_time on qrtz_triggers(SCHED_NAME,NEXT_FIRE_TIME);
create index idx_qrtz_t_nft_st on qrtz_triggers(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);
create index idx_qrtz_t_nft_misfire on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);
create index idx_qrtz_t_nft_st_misfire on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
create index idx_qrtz_t_nft_st_misfire_grp on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);
create index idx_qrtz_ft_trig_inst_name on qrtz_fired_triggers(SCHED_NAME,INSTANCE_NAME);
create index idx_qrtz_ft_inst_job_req_rcvry on qrtz_fired_triggers(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);
create index idx_qrtz_ft_j_g on qrtz_fired_triggers(SCHED_NAME,JOB_NAME,JOB_GROUP);
create index idx_qrtz_ft_jg on qrtz_fired_triggers(SCHED_NAME,JOB_GROUP);
create index idx_qrtz_ft_t_g on qrtz_fired_triggers(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
create index idx_qrtz_ft_tg on qrtz_fired_triggers(SCHED_NAME,TRIGGER_GROUP);
2. quartz. properties 파일 수정
이전 에는 이 설정 을 classpath 아래 에 두 지 않 았 습 니 다. 수정 후 에는 설정 을 classpath 아래 에 두 어야 합 니 다.
#============================================================================
# Configure Main Scheduler Properties
#============================================================================
org.quartz.scheduler.instanceName = DefaultQuartzScheduler
org.quartz.scheduler.instanceId = AUTO
#============================================================================
# Configure ThreadPool
#============================================================================
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
#============================================================================
# Configure JobStore
#============================================================================
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
##org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
#org.quartz.jobStore.useProperties = false
org.quartz.jobStore.dataSource = myDS
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.isClustered = false
#============================================================================
# Configure Datasources
#============================================================================
#org.quartz.dataSource.myDS.driver = org.postgresql.Driver
#org.quartz.dataSource.myDS.URL = jdbc:postgresql:dev
#org.quartz.dataSource.myDS.user = jhouse
#org.quartz.dataSource.myDS.password =
#org.quartz.dataSource.myDS.maxConnections = 5
#org.quartz.dataSource.myDS.validationQuery = select lock_name from qrtz_locks where lock_name = 'TRIGGER_ACCESS';
#============================================================================
# Configure Plugins
#============================================================================
# Uncomment the following to get logging of job execution events...
#org.quartz.plugin.jobHistory.class = org.quartz.plugins.history.LoggingJobHistoryPlugin
# Uncomment the following to get logging of trigger firing events...
#org.quartz.plugin.triggHistory.class = org.quartz.plugins.history.LoggingTriggerHistoryPlugin
#org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.JobInitializationPlugin
#org.quartz.plugin.jobInitializer.fileName = jobs.xml
#org.quartz.plugin.jobInitializer.overWriteExistingJobs = true
#org.quartz.plugin.jobInitializer.failOnFileNotFound = true
#org.quartz.plugin.jobInitializer.useContextClassLoader = true
#org.quartz.plugin.jobInitializer.validating = false
#org.quartz.plugin.jobInitializer.validatingSchema = true
#org.quartz.plugin.jobInitializer.scanInterval = 1800
#============================================================================
# Configure Listeners
#============================================================================
#org.quartz.jobListener.dummy.class = org.quartz.examples.DumbJobListener
3. spring 과 통합
applicationContext. xml 을 수정 하고 다음 설정 을 추가 합 니 다.
4. 모니터 추가
트리거 의 실행 상황 을 모니터링 해 야 하기 때문에 servlet 초기 화 에 모니터 를 추가 하 였 습 니 다.
private void initQuartz(ServletConfig cfg) {
System.out.println("Quartz ...");
try {
//
scheduler = (Scheduler)BeanLocator.getBeanInstance("bdcscheduler");
TriggerListener myListener=new MonitorTriggerListener();
scheduler.addGlobalTriggerListener(myListener);
System.out.println(" " + scheduler.getSchedulerName() + " ");
} catch (Exception e) {
System.out.println("Quartz : " + e.toString());
logger.error(e);
}
}
5. 기 존 jobs. xml 의 job 설정 정 보 를 데이터베이스 로 초기 화 합 니 다.
먼저 jobs. xml 를 분석 한 다음 jobdetail 과 crontrigger 로 초기 화하 고 scheduler. scheduleJob 을 순서대로 실행 합 니 다.
public static List filterJobXmlFile() throws Exception {
String configFileName = "jobs.xml";
String jobXmlFileFullName = ConfigContext.getFullConfigPath("quartz",configFileName);
// String jobXmlFileFullName = ConfigurationHelper.getFullFileName(configFile);
List simsJobList = new ArrayList();
logger.debug(" ( xml )");
// ( xml )
Document doc = FeatureFilterUtils.parseXMLFile(jobXmlFileFullName);
Element root = doc.getRootElement();
// ,
Namespace namespace = root.getNamespace();
root.removeNamespaceDeclaration(namespace);
// root.setNamespace(null);
// feature feature ( JOB )
// removeFeatureClose(root, namespace);
@SuppressWarnings("unchecked")
List list = root.getChildren("job",namespace);
for (Element element : list) {
SimsJob simsJob = new SimsJob();
@SuppressWarnings("unchecked")
List eleList = element.getChildren("job-detail",namespace);
Map paraMap = new HashMap();
for (Element ele : eleList) {
simsJob.setName(ele.getChild("name",namespace).getValue());
simsJob.setGroup(ele.getChild("group",namespace).getValue());
simsJob.setJobClass(ele.getChild("job-class",namespace).getValue());
simsJob.setVolatility(ele.getChild("volatility",namespace).getValue());
simsJob.setDurability(ele.getChild("durability",namespace).getValue());
simsJob.setRecover(ele.getChild("recover",namespace).getValue());
Element ele1 =ele.getChild("job-data-map",namespace);
if(ele1==null){
continue;
}
List ele2List = ele1.getChildren("entry",namespace);
for (Element ele3 : ele2List) {
String key = ele3.getChild("key",namespace).getValue();
String value = ele3.getChild("value",namespace).getValue();
paraMap.put(key, value);
}
}
simsJob.setParaMap(paraMap);
simsJob.setServiceName(paraMap.get("serviceName"));
String jobDesc = paraMap.get("desc");
if(StringUtils.isEmpty(jobDesc)){
jobDesc=" job , :"+simsJob.getName();
}
simsJob.setDesc(jobDesc);
Element trigger = element.getChild("trigger",namespace);
@SuppressWarnings("unchecked")
List triggerList = trigger.getChildren();
for (Element ele : triggerList) {
simsJob.setTriggerName(ele.getChild("name",namespace).getValue());
simsJob.setTriggerGroup(ele.getChild("group",namespace).getValue());
simsJob.setTriggerCronExpression(ele
.getChild("cron-expression",namespace).getValue());
}
simsJobList.add(simsJob);
}
return simsJobList;
}
/**
* xml
* initDbQuartz
* @param mapping
* @param form
* @param request
* @return
*/
public voidinitDbQuartz(ActionMapping mapping, ActionForm form, HttpServletRequest request) {
List jobList = null;
try {
jobList = SimsJobXmlUtil.filterJobXmlFile();
for (SimsJob simsJob : jobList) {
Class ownerClass = Class.forName(simsJob.getJobClass());
Constructor constructor = ownerClass.getConstructor();
Job job = (Job) constructor.newInstance();
// JOB
Scheduler scheduler = (Scheduler) BeanLocator.getBeanInstance("bdcscheduler");
TriggerListener myListener = new MonitorTriggerListener();
scheduler.addGlobalTriggerListener(myListener);
JobDetail jobDetail =
new JobDetail(simsJob.getName(), simsJob.getGroup(), job.getClass(), BooleanUtils.toBoolean(simsJob
.getVolatility()), BooleanUtils.toBoolean(simsJob.getDurability()),
BooleanUtils.toBoolean(simsJob.getRecover()));
jobDetail.setDescription(simsJob.getDesc());
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.putAll(simsJob.getParaMap());
jobDetail.setJobDataMap(jobDataMap);
Trigger trigger =
new CronTrigger(simsJob.getTriggerName(), simsJob.getTriggerGroup(), simsJob.getName(),
simsJob.getGroup(), simsJob.getTriggerCronExpression());
trigger.setDescription(simsJob.getDesc());
scheduler.scheduleJob(jobDetail, trigger);
}
} catch (Exception e) {
logger.error(" Job listSimsJobs ", e);
e.printStackTrace();
}
}
6. 수 동 실행
수 동 실행 이란 new simpletrigger 가 job 를 한 번 수행 하 는 것 입 니 다. 다음 과 같 습 니 다.
public static void runJob(String jobName) {
logger.debug(" Job doRunSimsJob runName:" + jobName);
try {
// JOB
Scheduler scheduler = (Scheduler) BeanLocator.getBeanInstance("bdcscheduler");
SimsJob simsJob = null;
boolean existFlag = false;
if (jobName != null && !"".equals(jobName)) {
// scheduler TriggerGroupNames
String[] triggerGroups = scheduler.getTriggerGroupNames();
for (int i = 0; i < triggerGroups.length; i++) {// ,
String groupName = triggerGroups[i];
//
String[] triggerNames = scheduler.getTriggerNames(groupName);
for (int j = 0; j < triggerNames.length; j++) {// ,
if (existFlag) {
break;
}
simsJob = new SimsJob();
String triggerName = triggerNames[j];
//
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerName, groupName);
if (jobName.equals(trigger.getJobName())) {
// TriggerDTO
simsJob.setDesc(trigger.getDescription());
simsJob.setGroup(trigger.getJobGroup());
simsJob.setName(trigger.getJobName());
JobDetail jobdetail=scheduler.getJobDetail(trigger.getJobName(), trigger.getJobGroup());
simsJob.setJobClass(jobdetail.getJobClass().getName());
simsJob.setParaMap(jobdetail.getJobDataMap());
simsJob.setTriggerGroup(trigger.getGroup());
simsJob.setTriggerName(trigger.getName());
simsJob.setTriggerCronExpression(trigger.getCronExpression());
existFlag = true;
}
}
if (existFlag) {
break;
}
}
}
if (existFlag) {
Class clazz=Class.forName(simsJob.getJobClass());
// Job
Constructor constructor = clazz.getConstructor();
Job job = (Job) constructor.newInstance();
TriggerListener myListener = new MonitorTriggerListener();
scheduler.addGlobalTriggerListener(myListener);
JobDetail jobDetail = new JobDetail(simsJob.getName(), Scheduler.DEFAULT_GROUP, job.getClass());
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.putAll(simsJob.getParaMap());
jobDetail.setJobDataMap(jobDataMap);
Trigger trigger =
new SimpleTrigger(simsJob.getTriggerName(), Scheduler.DEFAULT_GROUP, new Date(), null, 0, 0L);
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
logger.error(" Job :" + simsJob.getName() + " , !");
} else {
logger.error(" Job : Job Job , Job !");
}
} catch (Exception e) {
logger.error("doRunSimsJob Job ", e);
e.printStackTrace();
}
}
7, quartz 업그레이드
우리 가 사용 하 는 spring 버 전 은 3.2.16 이 고, spring 3.2.16 에 서 는 org. spring from work. scheduling. quartz. CrontriggerBean 은 org. quartz. CrontTrigger (Public class CronTrigger Beanextends CronTrigger) 를 계승 하 였 으 며, quartz 2.3.3 에 서 는 org. quartz. CrontTrigger 는 인터페이스 (Publicabstract interface CronTrigger extends Trigger) 입 니 다.한편, 우리 시스템 의 일부 라 이브 러 리 에 서 는 CronTriggerBean 을 사용 하여 CronTriggerBean 을 계승 하여 최신 버 전 quartz 2.3.3 타 임 스 오류 로 업그레이드 되 었 기 때문에 quartz 1.8.6 으로 만 업그레이드 되 었 다.
여기 서 특히 주의해 야 할 것 은 quartz 가 1.8.6 으로 업그레이드 한 후 xml 를 사용 해 야 한다 면 1.6 버 전과 큰 차이 가 있 을 수 있다 는 점 이다.아래 와 같다
1.6 버 전 은 다음 과 같다.
holidayCalendar
HolidayCalendar
weeklyCalendar
WeeklyCalendar
annualCalendar
AnnualCalendar
DataDictionaryCache
taskGroup
com.aspire.sims.uspc.platform.job.ScheduleServiceProcessor
false
false
false
serviceName
dataDictionaryCache
desc
uspc
DataDictionaryCacheTrigger
triggerGroup
DataDictionaryCache
taskGroup
0 0 23 * * ?
다음은 1.8.6.
approveNotifyJob
approveNotifyJob_group
sims job
com.aspire.bdc.common.job.ApproveNotifyJob
false
false
false
remind_spserv
spServApproveNotifyService
cronTrigger_approveNotifyJob
triggerGroup
sims
approveNotifyJob
approveNotifyJob_group
0 30 15 ? * MON,WED,FRI
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Spring 통합 Quartz의 간단한 구성 방법그러나 실제 업무에서 직접 그것을 사용하는 것은 매우 드물다.일반적으로spring-quartz 구성 요소를 사용하며, 직접 설정을 통해spring 프레임워크를 자동으로 조립합니다 다음은spring 프레임워크 통합qu...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.