๐ SchedulerFactoryBean ํด๋์ค๋ฅผ ํตํ Quartz Scheduler ๋ฑ๋ก
๐ SchedulerFactoryBean ์ด๋?
Quartz org.quartz.Scheduler, ๋ฅผ ์์ฑ ๋ฐ ์ค์ ํ๊ณ , ์คํ๋ง ์ ํ๋ฆฌ์ผ์ด์ ์ปจํ ์คํธ์ ์ผ๋ถ๋ก ๋ผ์ดํ์ฌ์ดํด์ ๊ด๋ฆฌํ๋ฉฐ, ์ข ์์ฑ ์ฃผ์ ์ ์ํ ๋น ์ฐธ์กฐ๋ก ์ค์ผ์ค๋ฌ๋ฅผ ๋ ธ์ถํ๋ FactoryBean. ์์ ์ธ๋ถ ์ ๋ณด, ์บ๋ฆฐ๋ ๋ฐ ํธ๋ฆฌ๊ฑฐ๋ฅผ ๋ฑ๋กํ ์ ์์ผ๋ฉฐ, ์ด๊ธฐํ ์ ์ค์ผ์ค๋ฌ๋ฅผ ์๋์ผ๋ก ์์ํ๊ณ ํ๊ดด ์ ์ข ๋ฃํ ์ ์์ต๋๋ค.
> ์ฆ, ์์ฑ ํ๋ฉด ์คํ๋ง์ด ์์์ ๊ด๋ฆฌํด์ค๋ค!
"์คํ๋ง์ IoC ์ปจํ ์ด๋์ ์ํด ๋น์ผ๋ก ์์ฑ๋๋ฉด, ์คํ๋ง์ด ํด๋น ๋น์ ๋ผ์ดํ์ฌ์ดํด์ ๊ด๋ฆฌํ๋ฏ๋ก ๊ฐ๋ฐ์๋ ์ค์ผ์ค๋ฌ์ ์์ฑ, ์ด๊ธฐํ, ์์, ์ข ๋ฃ ๋ฑ์ ์์ ์ ์๋์ผ๋ก ์ฒ๋ฆฌํ ํ์๊ฐ ์์ต๋๋ค."
IoC ์ปจํ ์ด๋์ ์ข ๋ฅ
์คํ๋ง์์๋ ์ฌ๋ฌ ๊ฐ์ง IoC ์ปจํ ์ด๋๋ฅผ ์ ๊ณตํ๋ฉฐ, ์ผ๋ฐ์ ์ผ๋ก ApplicationContext ๋ฅผ ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉ
BeanFactory | ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ IoC ์ปจํ ์ด๋๋ก, ์ง์ฐ ์ด๊ธฐํ(lazy loading) ๋ฐฉ์์ผ๋ก ๊ฐ์ฒด๋ฅผ ์์ฑํจ. |
ApplicationContext | BeanFactory๋ฅผ ํ์ฅํ ์ปจํ ์ด๋๋ก, ๋ถ๊ฐ์ ์ธ ๊ธฐ๋ฅ (AOP, ํธ๋์ญ์ , ๋ฉ์์ง์์ค ๋ฑ) ์ ์ง์ํจ. |
WebApplicationContext | ์น ์ ํ๋ฆฌ์ผ์ด์ ํ๊ฒฝ์์ ์ฌ์ฉ๋๋ IoC ์ปจํ ์ด๋. |
๐น SchedulerFactoryBean๊ณผ IoC ์ปจํ ์ด๋์ ๊ด๊ณ
๐ก SchedulerFactoryBean์ ApplicationContext์ ์ํด ๊ด๋ฆฌ๋๋ ํ๋์ ๋น(Bean) ์
๋๋ค.
์ฆ, ์คํ๋ง IoC ์ปจํ
์ด๋๊ฐ SchedulerFactoryBean์ ์๋ช
์ฃผ๊ธฐ๋ฅผ ์๋์ผ๋ก ๊ด๋ฆฌํ๋ฏ๋ก, ๊ฐ๋ฐ์๊ฐ ์ง์ Scheduler ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ์ข
๋ฃํ ํ์ ์์ด ์คํ๋ง์ด ์์์ ์์ฑํ๊ณ ์๋ฉธ์์ผ ์ค๋๋ค.
์ค์ผ์ค๋ฌ ์ค์ , Quartz ํธ๋ฆฌ๊ฑฐ ์ค์ ๋ถ๋ถ์ ๊ธฐ๋ก ํ์ผ๋ฉฐ,
์ค์ ์ ๋ฌด์ ์ฌ์ฉ๋๋ ์คํ ๋ก์ง์(Job) ์ํ๋ ๊ธฐ๋ฅ์ ํด๋์คํ์ผ์ ๊ตฌํํ๋ฉด๋จ. โก๏ธ ์ค์ผ์ค๋ฌ๊ฐ ์คํํ ๋ก์ง
(์ฌ๊ธฐ์๋ Myjob.class๋ก ๋์ค๋ฉฐ, ์ค์ผ์ค๋ฌ๋ก ๋์ํ ์๋น์ค ๋ก์ง์ด ์๋ ์ค์ผ์ค๋ฌ ๋ฑ๋ก์ด ๋ชฉ์ ์ด๋ฏ๋ก ์๋ตํ์์ต๋๋ค.)
1. pom.xml ์์กด์ฑ ์ฃผ์
<!-- quartz -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
2. Quartz ์ค์ผ์ค๋ฌ ๋ฑ๋ก
์์ ํ์ผ : QuartzConfigTest.java
์ค์ผ์ค๋ฌ๋ฅผ 3๊ฐ์ง ์์๋ก ๊ตฌ์ฑํด๋ณด๋ฉด ์ค์ผ์ค๋ฌ & ์คํ๋ด์ฉ์ธ Job & Job์ ์คํํ Trigger ์ด๋ค.
( ์ค์ผ์ค๋ฌ๋ฅผ ๋น์ผ๋ก ๋ฑ๋กํ๊ณ ํธ๋ฆฌ๊ฑฐ๋ฅผ ์ค์ ํด ํธ์ถํ๋ฉฐ, ํธ์ถํ Job ํด๋์ค ํ์ผ์ ์์ฑํ๋ฉด ๋!)
์ค์ผ์ค๋ฌ๋ฅผ ๋น์ผ๋ก ๋ฑ๋ก ํ ๋ ์๋ฐ ๊ธฐ๋ฐ์ผ๋ก ์ค์ ํด์ฃผ์๋ค. Spring์ @Configuration ์ด๋ ธํ ์ด์ ์ผ๋ก ์ค์ ํด๋์ค๋ฅผ ์ ์ ํ๊ณ , @Bean ์ด๋ ธํ ์ด์ ์ผ๋ก SchedulerFactoryBean์ ์ ์ํด ์ค์ผ์ค๋ฌ๋ฅผ ๋น์ผ๋ก ๋ฑ๋กํ๋ค. ์ด๋ ๊ฒ ์์ฑ๋ ์ค์ผ์ค๋ฌ๋ Spring ์ปจํ ์คํธ์ ์ผ๋ถ๋ก ๊ด๋ฆฌ๋๋ฉฐ, ์๋์ผ๋ก ์ด๊ธฐํ๋๊ณ ์ ํ๋ฆฌ์ผ์ด์ ์ข ๋ฃ ์ ์๋์ผ๋ก ์ข ๋ฃ๋๋ค.
์๋ ์ฝ๋๋ฅผ ๋ฐ๋ผ๊ฐ๋ฉฐ ์์ (Job)๊ณผ ํธ๋ฆฌ๊ฑฐ(Trigger)๋ฅผ ์ค์ ํ๋ ์ฝ๋๋ฅผ ๋ณด๋ฉด
JobDetailFactoryBean์ผ๋ก Quartz ์์ ์ ์ ์ํ๊ณ , CronTriggerFactoryBean์ ์ฌ์ฉํ์ฌ ํฌ๋ก ํํ์์ ๊ธฐ๋ฐ์ผ๋ก ํธ๋ฆฌ๊ฑฐ(์ธ์ ์คํ๋ ์ง)๋ฅผ ์ค์ ํ๋ค.
import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
@Configuration
public class QuartzConfigTest {
// โ JobDetailFactoryBean ์ผ๋ก Quartz ์์
์ ์ธ๋ถ ์ ๋ณด๋ฅผ ์ค์
@Bean
public JobDetailFactoryBean jobDetail() {
JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
factoryBean.setJobClass(MyJob.class); // ์์
ํด๋์ค ์ค์
// ์์
์ ์ด๋ฆ, ๊ทธ๋ฃน, ์ค๋ช
, ๋ด๊ตฌ์ฑ ์ฌ๋ถ(durability), ์ ์ฅ ์ฌ๋ถ ๋ฑ์ ์ค์
factoryBean.setDescription("Sample Quartz Job");
factoryBean.setDurability(true);
return factoryBean;
}
// โก CronTriggerFactoryBean ์ผ๋ก ํธ๋ฆฌ๊ฑฐ ์ค์ (์์
์คํ ์์ )
@Bean
public CronTriggerFactoryBean cronTrigger() {
CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean();
factoryBean.setJobDetail(jobDetail().getObject());
factoryBean.setCronExpression("0 0/5 * * * ?"); // ํฌ๋ก ํํ์์ผ๋ก ๋งค 5๋ถ๋ง๋ค ์คํ ์ ์
return factoryBean;
}
// โข SchedulerFactoryBean
@Bean
public SchedulerFactoryBean schedulerFactoryBean() {
Properties properties = new Properties(); // Quartz ์ค๋ ๋ ํ ์ค์ ์ ์ํ Properties ๊ฐ์ฒด ์์ฑ
// Quartz์ ์ค๋ ๋ ํ์ ํฌ๊ธฐ๋ฅผ 1๋ก ์ง์ .
// ์ฆ, ์ค๋ ๋ ํ์์ ํ ๋ฒ์ ํ๋์ ์ค๋ ๋๋ง ์คํ๋๋๋ก ํจ.
properties.setProperty("org.quartz.threadPool.threadCount", "1"); //Singleton ์ค๋ ๋ ์ฒ๋ฆฌ
// โ
SchedulerFactoryBean ๊ฐ์ฒด ์์ฑ.
// ์ด ๊ฐ์ฒด๋ Spring์์ Quartz ์ค์ผ์ค๋ฌ๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ํ ๋น์ด๋ค.
SchedulerFactoryBean scheduler = new SchedulerFactoryBean();
// Quartz ์ค์ผ์ค๋ฌ์ Properties ์ ์ฉ
scheduler.setQuartzProperties(properties);
// ํธ๋ฆฌ๊ฑฐ๋ฅผ ์ค์ผ์ค๋ฌ์ ์ค์
scheduler.setTriggers(cronTrigger().getObject());
// n๊ฐ์ ํธ๋ฆฌ๊ฑฐ๋ฅผ ์ค์ ์ ์ผํ๋ก ์ด์ด์ ์ค์ ๊ฐ๋ฅ
// ex) firstCronTrigger().getObject(), secondCronTrigger().getObject()
return scheduler; // ์ค์ ๋ SchedulerFactoryBean ๊ฐ์ฒด ๋ฐํ
}
}
@Configuration๊ณผ @Bean์ ์กฐํฉ์ ์คํ๋ง์ ํต์ฌ์ ์ธ ์ค์ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํ๋ฉฐ, ํนํ ํ๋ก์๋ฅผ ํตํ ์ฑ๊ธํค ๋ณด์ฅ์ด ๊ฐ๋ฅํด์ง๋๋ค.
@Bean ๋ฉ์๋์ ์ญํ : ์ปจํ ์ด๋๋ @Bean ์ด๋ ธํ ์ด์ ์ด ๋ถ์ ๋ฉ์๋๋ฅผ ์ฐพ์ ํด๋น ๋ฉ์๋๊ฐ ๋ฐํํ๋ ๊ฐ์ฒด๋ฅผ Spring ์ ํ๋ฆฌ์ผ์ด์ ์ปจํ ์คํธ์ ๋น์ผ๋ก ๋ฑ๋กํฉ๋๋ค.
โ ์ปจํ ์ด๋๊ฐ ๋น์ ๋ฑ๋กํ๊ณ ๊ด๋ฆฌํ๋ ๊ณผ์ ์ ๋ํด์ ํท๊ฐ๋ฆฐ๋ค๋ฉด ์๋ ๋ธ๋ก๊ทธ๋ฅผ ์ถ์ฒํ๋ฉฐ ์ถ์ฒ ๋จ๊น๋๋ค.
- ๋จผ์ @Configuration์ด ๋ถ์ ํด๋์ค๋ฅผ ์ฐพ์ต๋๋ค. ์ด ํด๋์ค๋ค์ด ์ค์ ์ ๋ณด๋ฅผ ๋ด๊ณ ์์ต๋๋ค.
- ๊ทธ๋ค์ @Component, @Controller, @Service, @Repository ๋ฑ์ ์ด๋ ธํ ์ด์ ์ด ๋ถ์ ํด๋์ค๋ค์ ์ฐพ์์ ๋น์ผ๋ก ๋ฑ๋กํฉ๋๋ค.
- @Bean์ด ๋ถ์ ๋ฉ์๋๋ค์ ์ฐพ์ ๊ทธ ๋ฉ์๋๊ฐ ๋ฐํํ๋ ๊ฐ์ฒด๋ค๋ ๋น์ผ๋ก ๋ฑ๋กํฉ๋๋ค.
- ์ด๋ ๊ฒ ๋ฑ๋ก๋ ๋น๋ค์ ์์กด๊ด๊ณ๋ฅผ ๋ถ์ํ๊ณ ํ์ํ ๊ฒฝ์ฐ ์๋์ผ๋ก ์ฃผ์ ํด ์ค๋๋ค.
โ ์ถ์ฒ: https://curiousjinan.tistory.com/entry/deep-dive-spring-container-configuration-and-bean#๋น์ ๋ฒ์(Scope)๋%3F-1 [์ค๋๋ ๊ฐ๋ฐ์ค์ ๋๋ค:ํฐ์คํ ๋ฆฌ]
3. Job.class ์์ฑ
์ ์์ ์์ค์์๋ MyJob.class๋ผ๋ ์ด๋ฆ์ผ๋ก ๊ธฐ๋ฅํ๊ณ ์ ํ๋ ๋ก์ง์ ๊ตฌ์ฑํด ์์ฑํ๋ฉด ๋๋ค.
(์๋น์ค ๋ก์ง.. ๋ฐ๋ณต๋ฌธ์ ๋๋ฉฐ db๋ฅผ ์กฐํํ์ฌ ์ฟ ํฐ์ ๋ฐ๊ธํ๋ค ๋ฑ๋ฑ. ์ค์ผ์ค๋ฌ๊ฐ ์คํ๋๋ฉฐ ์ํํด์ผ ํ ๋ก์ง์ ์์ฑ)
โ Scheduler ๋ฑ๋ก ๋ฐฉ๋ฒ์ ๋ํ ์ถ๊ฐ ๋ฉ๋ชจ
์ค์ผ์ค๋ฌ๋ Quartz์ ํต์ฌ ์ธํฐํ์ด์ค๋ก, ์ก(Job)์ ์ค์ผ์ค๋งํ๊ณ ๊ด๋ฆฌํ๋ ์ญํ ์ ํ๋ค.
Quartz ์ค์ผ์ค๋ฌ์์ Scheduler๋ฅผ ์ธ์คํด์คํํ๊ณ ์ฌ์ฉํ๋ ๋ํ์ ์ฌ์ฉ๋ฒ์ด ๋๊ฐ์ง๊ฐ ์๋๋ฐ
์ฒซ์งธ, StdSchedulerFactory ๋ก ์ง์ ์ธ์คํด์คํ ํด ์ฌ์ฉํ๋ ๊ฒ์ด๊ณ
๋์งธ, ์ด ํฌ์คํ ์ ์ค๋ช ํ ๋ด์ฉ์ผ๋ก SchedulerFactoryBean ์ ์ฌ์ฉํ์ฌ ์ค์ผ์ค๋ฌ๋ฅผ Spring ์ปจํ ์คํธ์ Bean์ผ๋ก ๋ฑ๋กํ๊ณ , ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ์ด๋ค.
๋๋ฒ์งธ ๋ฐฉ๋ฒ์ด ๋ ์ฝ๊ฒ ์ค์ผ์ค๋ง ์์ ์ ์ค์ ํ๊ณ ๊ด๋ฆฌํ ์ ์๋ค๊ณ ํ์ฌ ์ฌ์ฉํ๋๋ฐ ์ค์ ๋ก ์ฝ๋ ์์ฑ ๊ตฌ์กฐ๊ฐ ๋จ์ผํ ๋๊ธฐ ๋๋ฌธ์ ๋ค๋ฅธ ์ฌ๋์ด ์์ฑํ ์ฝ๋๋ฅผ ์์๋ณด๊ธฐ๋ ์ฌ์ด ๊ฒ ๊ฐ๋ค.
์ฒซ๋ฒ์งธ ๋ฐฉ๋ฒ, StdSchedulerFactory
StdSchedulerFactory๋ฅผ ์ฌ์ฉํ์ฌ ์ง์ Scheduler ์ธ์คํด์คํ ํ๋ ๋ฐฉ๋ฒ.
์ด ํฉํ ๋ฆฌ๋ ๋ด๋ถ์ ์ผ๋ก Quartz ์ค์ ํ์ผ์ ์ฝ์ด ์ค์ผ์ค๋ฌ๋ฅผ ์ด๊ธฐํ ํจ.
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
public class QuartzStdSchedulerExample {
public static void main(String[] args) {
try {
// SchedulerFactory๋ฅผ ํตํด ๊ธฐ๋ณธ Scheduler ์ธ์คํด์ค๋ฅผ ์์ฑํฉ๋๋ค.
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
// ์์
(Job) ์ ์
JobDetail job = JobBuilder.newJob(MyJob.class)
.withIdentity("myJob", "group1")
.build();
// ํธ๋ฆฌ๊ฑฐ ์ ์ (10์ด๋ง๋ค ์คํ)
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(10)
.repeatForever())
.build();
// ์ค์ผ์ค๋ฌ์ ์์
๊ณผ ํธ๋ฆฌ๊ฑฐ๋ฅผ ์ค์ผ์ค๋ง
scheduler.scheduleJob(job, trigger);
// ๋ค๋ฅธ ์์
์ถ๊ฐ ๋๋ ์ค์ผ์ค๋ฌ ์ ์ง ์์
์ํ...
// ์ค์ผ์ค๋ฌ ์ข
๋ฃ (ํ์ํ ๋)
scheduler.shutdown(true);
} catch (SchedulerException se) {
se.printStackTrace();
}
}
}
๋๋ฒ์งธ ๋ฐฉ๋ฒ, SchedulerFactoryBean
* Spring์ SchedulerFactoryBean์ ํตํด Quartz ์ค์ผ์ค๋ฌ๋ฅผ ๊ด๋ฆฌํ๋ฉฐ, ์ด ๋ฐฉ์์ Spring ์ ํ๋ฆฌ์ผ์ด์ ๋ด์์ Quartz ์์ ์ ํตํฉ ๊ด๋ฆฌํ๊ธฐ์ ์ ํฉํจ.
SchedulerFactoryBean
FactoryBean that creates and configures a Quartz org.quartz.Scheduler, manages its lifecycle as part of the Spring application context, and exposes the Scheduler as bean reference for dependency injection. Allows registration of JobDetails, Calendars and T
docs.spring.io
@Bean
public SchedulerFactoryBean scheduler(Trigger trigger, JobDetail job, DataSource quartzDataSource) {
SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean();
schedulerFactory.setConfigLocation(new ClassPathResource("quartz.properties"));
schedulerFactory.setJobFactory(springBeanJobFactory());
// JobDetail ๋ฐ Trigger ๋ฑ๋ก
schedulerFactory.setJobDetails(job);
schedulerFactory.setTriggers(trigger);
schedulerFactory.setDataSource(quartzDataSource);
return schedulerFactory;
}
์ด์ Spring ์ ํ๋ฆฌ์ผ์ด์ ์ปจํ ์คํธ๊ฐ ์์๋ ๋, SchedulerFactoryBean์ด ์๋์ผ๋ก Quartz ์ค์ผ์ค๋ฌ๋ฅผ ์ด๊ธฐํํ๊ณ ์์ํ๋ค. Spring์ด ์ค์ผ์ค๋ฌ์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๊ด๋ฆฌํ๋ฏ๋ก, ๋ณ๋์ ์ฝ๋๋ก ์ค์ผ์ค๋ฌ๋ฅผ ์์ํ๊ฑฐ๋ ์ข ๋ฃํ ํ์๊ฐ ์๋ค.