diff --git a/batch-quartz/src/main/java/com/spring/common/util/ApplicationUtil.java b/batch-quartz/src/main/java/com/spring/common/util/ApplicationUtil.java new file mode 100644 index 0000000..59f0292 --- /dev/null +++ b/batch-quartz/src/main/java/com/spring/common/util/ApplicationUtil.java @@ -0,0 +1,63 @@ +package com.spring.common.util; + +import org.springframework.web.context.ContextLoader; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ApplicationUtil { + + public static ServletRequestAttributes getServletRequestAttributes(){ + return (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); + } + //Request 객체 얻기 + public static HttpServletRequest getRequest(){ + return getServletRequestAttributes().getRequest(); + } + + //Set Request Attribute + public static void setRequestAttributes(String key, Object obj){ + getServletRequestAttributes().setAttribute(key, obj, RequestAttributes.SCOPE_REQUEST); + } + //Get Request Attribute + public static Object getRequestAttributes(String key){ + return getServletRequestAttributes().getAttribute(key, RequestAttributes.SCOPE_REQUEST); + } + + //Session 객체 얻기 + public static HttpSession getSession(){ + return getRequest().getSession(); + } + + //Set Session Attributes + public static void setSessionAttributes(String key, Object obj){ + getServletRequestAttributes().setAttribute(key, obj, RequestAttributes.SCOPE_SESSION); + } + + //Get Session Attributes + public static Object getSessionAttributes(String key){ + return getServletRequestAttributes().getAttribute(key, RequestAttributes.SCOPE_SESSION); + } + + //HttpServletResponse 객체 얻기 + public static HttpServletResponse getResponse(){ + return getServletRequestAttributes().getResponse(); + } + + //beanName을 통해서 Bean을 얻을 수 있다. + public static Object getBean(String beanName){ + var context = ContextLoader.getCurrentWebApplicationContext(); + if (context == null) { + throw new IllegalStateException("WebApplicationContext를 찾을 수 없습니다."); + } + return context.getBean(beanName); + } + +} diff --git a/batch-quartz/src/main/java/com/spring/domain/batch/entity/BatchJobExecution.java b/batch-quartz/src/main/java/com/spring/domain/batch/entity/BatchJobExecution.java index 2b7b368..fc77bdd 100644 --- a/batch-quartz/src/main/java/com/spring/domain/batch/entity/BatchJobExecution.java +++ b/batch-quartz/src/main/java/com/spring/domain/batch/entity/BatchJobExecution.java @@ -13,8 +13,8 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import lombok.Getter; -@Entity -@Table(name = "BATCH_JOB_EXECUTION") +// @Entity +// @Table(name = "BATCH_JOB_EXECUTION") @Getter public class BatchJobExecution { diff --git a/batch-quartz/src/main/java/com/spring/domain/batch/entity/BatchJobExecutionContext.java b/batch-quartz/src/main/java/com/spring/domain/batch/entity/BatchJobExecutionContext.java index f52e2ab..794fe9c 100644 --- a/batch-quartz/src/main/java/com/spring/domain/batch/entity/BatchJobExecutionContext.java +++ b/batch-quartz/src/main/java/com/spring/domain/batch/entity/BatchJobExecutionContext.java @@ -9,8 +9,8 @@ import jakarta.persistence.OneToOne; import jakarta.persistence.Table; import lombok.Getter; -@Entity -@Table(name = "BATCH_JOB_EXECUTION_CONTEXT") +// @Entity +// @Table(name = "BATCH_JOB_EXECUTION_CONTEXT") @Getter public class BatchJobExecutionContext { diff --git a/batch-quartz/src/main/java/com/spring/domain/batch/entity/BatchJobExecutionParams.java b/batch-quartz/src/main/java/com/spring/domain/batch/entity/BatchJobExecutionParams.java index 96be124..f60f775 100644 --- a/batch-quartz/src/main/java/com/spring/domain/batch/entity/BatchJobExecutionParams.java +++ b/batch-quartz/src/main/java/com/spring/domain/batch/entity/BatchJobExecutionParams.java @@ -13,8 +13,8 @@ import jakarta.persistence.Table; import lombok.EqualsAndHashCode; import lombok.Getter; -@Entity -@Table(name = "BATCH_JOB_EXECUTION_PARAMS") +// @Entity +// @Table(name = "BATCH_JOB_EXECUTION_PARAMS") @Getter public class BatchJobExecutionParams { diff --git a/batch-quartz/src/main/java/com/spring/domain/batch/entity/BatchJobInstance.java b/batch-quartz/src/main/java/com/spring/domain/batch/entity/BatchJobInstance.java index 46e77d2..135ba06 100644 --- a/batch-quartz/src/main/java/com/spring/domain/batch/entity/BatchJobInstance.java +++ b/batch-quartz/src/main/java/com/spring/domain/batch/entity/BatchJobInstance.java @@ -9,9 +9,9 @@ import jakarta.persistence.Table; import jakarta.persistence.UniqueConstraint; import lombok.Getter; -@Entity -@Table(name = "BATCH_JOB_INSTANCE", - uniqueConstraints = @UniqueConstraint(name = "JOB_INST_UN", columnNames = {"JOB_NAME", "JOB_KEY"})) +// @Entity +// @Table(name = "BATCH_JOB_INSTANCE", +// uniqueConstraints = @UniqueConstraint(name = "JOB_INST_UN", columnNames = {"JOB_NAME", "JOB_KEY"})) @Getter public class BatchJobInstance { diff --git a/batch-quartz/src/main/java/com/spring/domain/batch/entity/BatchStepExecution.java b/batch-quartz/src/main/java/com/spring/domain/batch/entity/BatchStepExecution.java index b849301..d700071 100644 --- a/batch-quartz/src/main/java/com/spring/domain/batch/entity/BatchStepExecution.java +++ b/batch-quartz/src/main/java/com/spring/domain/batch/entity/BatchStepExecution.java @@ -13,8 +13,8 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import lombok.Getter; -@Entity -@Table(name = "BATCH_STEP_EXECUTION") +// @Entity +// @Table(name = "BATCH_STEP_EXECUTION") @Getter public class BatchStepExecution { diff --git a/batch-quartz/src/main/java/com/spring/domain/batch/entity/BatchStepExecutionContext.java b/batch-quartz/src/main/java/com/spring/domain/batch/entity/BatchStepExecutionContext.java index b5393a1..fdf959e 100644 --- a/batch-quartz/src/main/java/com/spring/domain/batch/entity/BatchStepExecutionContext.java +++ b/batch-quartz/src/main/java/com/spring/domain/batch/entity/BatchStepExecutionContext.java @@ -9,8 +9,8 @@ import jakarta.persistence.OneToOne; import jakarta.persistence.Table; import lombok.Getter; -@Entity -@Table(name = "BATCH_STEP_EXECUTION_CONTEXT") +// @Entity +// @Table(name = "BATCH_STEP_EXECUTION_CONTEXT") @Getter public class BatchStepExecutionContext { diff --git a/batch-quartz/src/main/java/com/spring/domain/email/batch/EmailSendBatch.java b/batch-quartz/src/main/java/com/spring/domain/email/batch/EmailSendBatch.java new file mode 100644 index 0000000..8b85e15 --- /dev/null +++ b/batch-quartz/src/main/java/com/spring/domain/email/batch/EmailSendBatch.java @@ -0,0 +1,51 @@ +package com.spring.domain.email.batch; + +import org.springframework.batch.core.Job; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.job.builder.JobBuilder; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.step.builder.StepBuilder; +import org.springframework.batch.core.step.tasklet.Tasklet; +import org.springframework.batch.repeat.RepeatStatus; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.PlatformTransactionManager; + +import com.spring.infra.quartz.QuartzJob; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Configuration +@RequiredArgsConstructor +public class EmailSendBatch { + + private final JobRepository jobRepository; + private final PlatformTransactionManager transactionManager; + + @QuartzJob(name = "emailSendJob", cronExpression = "*/3 * * * * ?") + @Bean(name = "emailSendJob") + Job emailSendJob(Step emailSendStep) { + log.info(">>> emailSendJob"); + return new JobBuilder("emailSendJob", jobRepository) + .start(emailSendStep) + .build(); + } + + @Bean("emailSendStep") + Step emailSendStep(Tasklet emailSendTasklet) { + log.info(">>> emailSendStep"); + return new StepBuilder("emailSendStep", jobRepository) + .tasklet(emailSendTasklet, transactionManager).build(); + } + + @Bean + Tasklet emailSendTasklet(){ + return ((contribution, chunkContext) -> { + log.info(">>>>> emailSendTasklet"); + return RepeatStatus.FINISHED; + }); + } + +} diff --git a/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzBlobTriggers.java b/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzBlobTriggers.java index 3afd7f9..a00c2fc 100644 --- a/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzBlobTriggers.java +++ b/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzBlobTriggers.java @@ -12,8 +12,8 @@ import jakarta.persistence.Table; import lombok.EqualsAndHashCode; import lombok.Getter; -@Entity -@Table(name = "QRTZ_BLOB_TRIGGERS") +// @Entity +// @Table(name = "QRTZ_BLOB_TRIGGERS") @Getter public class QrtzBlobTriggers { diff --git a/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzCalendars.java b/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzCalendars.java index a68773a..db6af16 100644 --- a/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzCalendars.java +++ b/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzCalendars.java @@ -10,8 +10,8 @@ import jakarta.persistence.Table; import lombok.EqualsAndHashCode; import lombok.Getter; -@Entity -@Table(name = "QRTZ_CALENDARS") +// @Entity +// @Table(name = "QRTZ_CALENDARS") @Getter public class QrtzCalendars { diff --git a/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzCronTriggers.java b/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzCronTriggers.java index ecb2283..4fdc724 100644 --- a/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzCronTriggers.java +++ b/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzCronTriggers.java @@ -14,8 +14,8 @@ import jakarta.persistence.Table; import lombok.EqualsAndHashCode; import lombok.Getter; -@Entity -@Table(name = "QRTZ_CRON_TRIGGERS") +// @Entity +// @Table(name = "QRTZ_CRON_TRIGGERS") @Getter public class QrtzCronTriggers { diff --git a/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzFiredTriggers.java b/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzFiredTriggers.java index 95d7306..957d761 100644 --- a/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzFiredTriggers.java +++ b/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzFiredTriggers.java @@ -10,8 +10,8 @@ import jakarta.persistence.Table; import lombok.EqualsAndHashCode; import lombok.Getter; -@Entity -@Table(name = "QRTZ_FIRED_TRIGGERS") +// @Entity +// @Table(name = "QRTZ_FIRED_TRIGGERS") @Getter public class QrtzFiredTriggers { diff --git a/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzJobDetails.java b/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzJobDetails.java index f0efbc4..b59ba79 100644 --- a/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzJobDetails.java +++ b/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzJobDetails.java @@ -10,8 +10,8 @@ import jakarta.persistence.Table; import lombok.EqualsAndHashCode; import lombok.Getter; -@Entity -@Table(name = "QRTZ_JOB_DETAILS") +// @Entity +// @Table(name = "QRTZ_JOB_DETAILS") @Getter public class QrtzJobDetails { diff --git a/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzLocks.java b/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzLocks.java index 184646f..3ae8de4 100644 --- a/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzLocks.java +++ b/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzLocks.java @@ -10,8 +10,8 @@ import jakarta.persistence.Table; import lombok.EqualsAndHashCode; import lombok.Getter; -@Entity -@Table(name = "QRTZ_LOCKS") +// @Entity +// @Table(name = "QRTZ_LOCKS") @Getter public class QrtzLocks { diff --git a/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzPausedTriggerGrps.java b/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzPausedTriggerGrps.java index f7189a9..6a4e7df 100644 --- a/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzPausedTriggerGrps.java +++ b/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzPausedTriggerGrps.java @@ -10,8 +10,8 @@ import jakarta.persistence.Table; import lombok.EqualsAndHashCode; import lombok.Getter; -@Entity -@Table(name = "QRTZ_PAUSED_TRIGGER_GRPS") +// @Entity +// @Table(name = "QRTZ_PAUSED_TRIGGER_GRPS") @Getter public class QrtzPausedTriggerGrps { diff --git a/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzSchedulerState.java b/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzSchedulerState.java index 98a8769..8d8392e 100644 --- a/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzSchedulerState.java +++ b/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzSchedulerState.java @@ -10,8 +10,8 @@ import jakarta.persistence.Table; import lombok.EqualsAndHashCode; import lombok.Getter; -@Entity -@Table(name = "QRTZ_SCHEDULER_STATE") +// @Entity +// @Table(name = "QRTZ_SCHEDULER_STATE") @Getter public class QrtzSchedulerState { diff --git a/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzSimpleTriggers.java b/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzSimpleTriggers.java index 7fb92f3..f259417 100644 --- a/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzSimpleTriggers.java +++ b/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzSimpleTriggers.java @@ -14,8 +14,8 @@ import jakarta.persistence.Table; import lombok.EqualsAndHashCode; import lombok.Getter; -@Entity -@Table(name = "QRTZ_SIMPLE_TRIGGERS") +// @Entity +// @Table(name = "QRTZ_SIMPLE_TRIGGERS") @Getter public class QrtzSimpleTriggers { diff --git a/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzSimpropTriggers.java b/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzSimpropTriggers.java index 62f5ac8..c112e58 100644 --- a/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzSimpropTriggers.java +++ b/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzSimpropTriggers.java @@ -15,8 +15,8 @@ import jakarta.persistence.Table; import lombok.EqualsAndHashCode; import lombok.Getter; -@Entity -@Table(name = "QRTZ_SIMPROP_TRIGGERS") +// @Entity +// @Table(name = "QRTZ_SIMPROP_TRIGGERS") @Getter public class QrtzSimpropTriggers { diff --git a/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzTriggers.java b/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzTriggers.java index 8bcc98c..2f9bfb3 100644 --- a/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzTriggers.java +++ b/batch-quartz/src/main/java/com/spring/domain/quartz/entity/QrtzTriggers.java @@ -14,8 +14,8 @@ import jakarta.persistence.Table; import lombok.EqualsAndHashCode; import lombok.Getter; -@Entity -@Table(name = "QRTZ_TRIGGERS") +// @Entity +// @Table(name = "QRTZ_TRIGGERS") @Getter public class QrtzTriggers { diff --git a/batch-quartz/src/main/java/com/spring/infra/batch/AbstractBatchConfig.java b/batch-quartz/src/main/java/com/spring/infra/batch/AbstractBatchConfig.java deleted file mode 100644 index ff42902..0000000 --- a/batch-quartz/src/main/java/com/spring/infra/batch/AbstractBatchConfig.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.spring.infra.batch; - -import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; -import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; -import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Configuration; - -@Configuration -@EnableBatchProcessing -public abstract class AbstractBatchConfig { - - @Autowired - protected JobBuilderFactory jobBuilderFactory; - - @Autowired - protected StepBuilderFactory stepBuilderFactory; - -} diff --git a/batch-quartz/src/main/java/com/spring/infra/quartz/QuartzConfig.java b/batch-quartz/src/main/java/com/spring/infra/quartz/QuartzConfig.java index 012b807..2dd76c3 100644 --- a/batch-quartz/src/main/java/com/spring/infra/quartz/QuartzConfig.java +++ b/batch-quartz/src/main/java/com/spring/infra/quartz/QuartzConfig.java @@ -6,8 +6,6 @@ import org.quartz.Job; import org.quartz.Scheduler; import org.quartz.spi.JobFactory; import org.quartz.spi.TriggerFiredBundle; -import org.springframework.batch.core.configuration.JobRegistry; -import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -23,20 +21,7 @@ public class QuartzConfig { private final QuartzProperties quartzProperties; private final DataSource dataSource; private final PlatformTransactionManager transactionManager; - - /** - * JobRegistry 에 Job 을 자동으로 등록하기 위한 설정. - * - * @param jobRegistry ths Spring Batch Job Registry - * @return JobRegistry BeanPostProcessor - */ - @Bean - JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor(JobRegistry jobRegistry) { - var jobRegistryBeanPostProcessor = new JobRegistryBeanPostProcessor(); - jobRegistryBeanPostProcessor.setJobRegistry(jobRegistry); - return jobRegistryBeanPostProcessor; - } - + /** * Quartz Schedule Job 에 의존성 주입 * @@ -55,10 +40,8 @@ public class QuartzConfig { /** * Scheduler 전체를 관리하는 Manager. * - * @param datasource Spring datasource - * @param quartzProperties quartz config + * @param jobFactory job factory * @return the scheduler factory bean - * @throws Exception the exception */ @Bean SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory) { diff --git a/batch-quartz/src/main/java/com/spring/infra/quartz/QuartzJobLauncher.java b/batch-quartz/src/main/java/com/spring/infra/quartz/QuartzJobLauncher.java index 4b31927..57e866a 100644 --- a/batch-quartz/src/main/java/com/spring/infra/quartz/QuartzJobLauncher.java +++ b/batch-quartz/src/main/java/com/spring/infra/quartz/QuartzJobLauncher.java @@ -5,36 +5,34 @@ import org.quartz.JobExecutionException; import org.springframework.batch.core.Job; import org.springframework.batch.core.JobParameters; import org.springframework.batch.core.JobParametersBuilder; -import org.springframework.batch.core.configuration.JobLocator; +import org.springframework.batch.core.configuration.JobRegistry; import org.springframework.batch.core.launch.JobLauncher; import org.springframework.lang.NonNull; import org.springframework.scheduling.quartz.QuartzJobBean; +import org.springframework.stereotype.Component; +import lombok.RequiredArgsConstructor; + +@Component +@RequiredArgsConstructor public class QuartzJobLauncher extends QuartzJobBean { + private final JobLauncher jobLauncher; + private final JobRegistry jobRegistry; + private String jobName; - private JobLauncher jobLauncher; - private JobLocator jobLocator; public void setJobName(String jobName) { this.jobName = jobName; } - public void setJobLauncher(JobLauncher jobLauncher) { - this.jobLauncher = jobLauncher; - } - - public void setJobLocator(JobLocator jobLocator) { - this.jobLocator = jobLocator; - } - @Override protected void executeInternal(@NonNull JobExecutionContext context) throws JobExecutionException { try { - Job job = jobLocator.getJob(jobName); + Job job = jobRegistry.getJob(jobName); JobParameters params = new JobParametersBuilder() - .addString("JobID", String.valueOf(System.currentTimeMillis())) - .toJobParameters(); + .addString("JobID", String.valueOf(System.currentTimeMillis())) + .toJobParameters(); jobLauncher.run(job, params); } catch (Exception e) { throw new JobExecutionException(e); diff --git a/batch-quartz/src/main/java/com/spring/infra/quartz/QuartzJobRegistrar.java b/batch-quartz/src/main/java/com/spring/infra/quartz/QuartzJobRegistrar.java index 1098b03..a56abf3 100644 --- a/batch-quartz/src/main/java/com/spring/infra/quartz/QuartzJobRegistrar.java +++ b/batch-quartz/src/main/java/com/spring/infra/quartz/QuartzJobRegistrar.java @@ -10,43 +10,34 @@ import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.Trigger; import org.quartz.TriggerBuilder; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.core.annotation.AnnotationUtils; import org.springframework.lang.NonNull; import org.springframework.stereotype.Component; +import lombok.RequiredArgsConstructor; + @Component -public class QuartzJobRegistrar implements ApplicationContextAware, InitializingBean { +@RequiredArgsConstructor +public class QuartzJobRegistrar implements ApplicationListener { - private ApplicationContext applicationContext; - private Scheduler scheduler; - - public QuartzJobRegistrar(Scheduler scheduler) { - this.scheduler = scheduler; - } + private final Scheduler scheduler; + private final ApplicationContext applicationContext; @Override - public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - } - - @Override - public void afterPropertiesSet() { - registerQuartzJobs(); - } - - private void registerQuartzJobs() { - applicationContext.getBeansWithAnnotation(QuartzJob.class).forEach((beanName, bean) -> { + public void onApplicationEvent(@NonNull ContextRefreshedEvent event) { + for (String beanName : applicationContext.getBeanDefinitionNames()) { + Object bean = applicationContext.getBean(beanName); Class beanClass = bean.getClass(); - for (Method method : beanClass.getMethods()) { - QuartzJob quartzJobAnnotation = method.getAnnotation(QuartzJob.class); + for (Method method : beanClass.getDeclaredMethods()) { + QuartzJob quartzJobAnnotation = AnnotationUtils.findAnnotation(method, QuartzJob.class); if (quartzJobAnnotation != null) { registerQuartzJob(quartzJobAnnotation, method.getName()); } } - }); + } } private void registerQuartzJob(QuartzJob quartzJobAnnotation, String jobName) { @@ -55,6 +46,7 @@ public class QuartzJobRegistrar implements ApplicationContextAware, Initializing Trigger trigger = createTrigger(quartzJobAnnotation, jobDetail); scheduler.scheduleJob(jobDetail, trigger); } catch (SchedulerException e) { + e.printStackTrace(); throw new IllegalStateException("Error scheduling Quartz job", e); } } @@ -62,8 +54,6 @@ public class QuartzJobRegistrar implements ApplicationContextAware, Initializing private JobDetail createJobDetail(QuartzJob quartzJobAnnotation, String jobName) { JobDataMap jobDataMap = new JobDataMap(); jobDataMap.put("jobName", jobName); - jobDataMap.put("jobLauncher", applicationContext.getBean("jobLauncher")); - jobDataMap.put("jobLocator", applicationContext.getBean("jobLocator")); return JobBuilder.newJob(QuartzJobLauncher.class) .withIdentity(quartzJobAnnotation.name()) .setJobData(jobDataMap) diff --git a/batch-quartz/src/main/java/com/spring/infra/quartz/QuartzProperties.java b/batch-quartz/src/main/java/com/spring/infra/quartz/QuartzProperties.java index b062325..173b60a 100644 --- a/batch-quartz/src/main/java/com/spring/infra/quartz/QuartzProperties.java +++ b/batch-quartz/src/main/java/com/spring/infra/quartz/QuartzProperties.java @@ -54,9 +54,7 @@ public class QuartzProperties { private void addProperties(String prefix, Object object, Properties properties) { Arrays.stream(object.getClass().getDeclaredFields()) .filter(field -> !Modifier.isStatic(field.getModifiers())) - .forEach(field -> { - setProperties(prefix, object, properties, field); - }); + .forEach(field -> setProperties(prefix, object, properties, field)); } private void setProperties(String prefix, Object object, Properties properties, Field field) { diff --git a/batch-quartz/src/main/java/com/spring/infra/security/config/SecurityConfig.java b/batch-quartz/src/main/java/com/spring/infra/security/config/SecurityConfig.java index 8021605..4c3e4d5 100644 --- a/batch-quartz/src/main/java/com/spring/infra/security/config/SecurityConfig.java +++ b/batch-quartz/src/main/java/com/spring/infra/security/config/SecurityConfig.java @@ -1,5 +1,7 @@ package com.spring.infra.security.config; +import java.util.List; + import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; @@ -29,7 +31,7 @@ import lombok.RequiredArgsConstructor; @RequiredArgsConstructor public class SecurityConfig { - public static final String PERMITTED_URI[] = {"/api/auth/**", "/signIn"}; + private static final String[] PERMITTED_URI = {"/favicon.ico", "/api/auth/**", "/signIn", "/h2-console/**"}; @Bean SecurityFilterChain securityFilterChain( @@ -47,20 +49,23 @@ public class SecurityConfig { .requestMatchers(PERMITTED_URI).permitAll() .anyRequest().authenticated() ) - .logout((logout) -> logout + .logout(logout -> logout .logoutSuccessUrl("/signIn") .invalidateHttpSession(true)) .sessionManagement(session -> session .sessionCreationPolicy(SessionCreationPolicy.STATELESS) ) - .addFilterBefore(new JwtAuthenticationFilter(tokenService), UsernamePasswordAuthenticationFilter.class) - .exceptionHandling(ex -> ex.authenticationEntryPoint(authenticationEntryPoint).accessDeniedHandler(accessDeniedHandler)); + .addFilterBefore(new JwtAuthenticationFilter(tokenService, List.of(PERMITTED_URI)), UsernamePasswordAuthenticationFilter.class) + .exceptionHandling(ex -> ex + .authenticationEntryPoint(authenticationEntryPoint) + .accessDeniedHandler(accessDeniedHandler) + ); return http.build(); } @Bean WebSecurityCustomizer ignoringCustomizer() { - return (web) -> web.ignoring().requestMatchers("/h2-console/**"); + return web -> web.ignoring().requestMatchers("/h2-console/**"); } @Bean diff --git a/batch-quartz/src/main/java/com/spring/infra/security/filter/JwtAuthenticationFilter.java b/batch-quartz/src/main/java/com/spring/infra/security/filter/JwtAuthenticationFilter.java index fb0bb81..19deef0 100644 --- a/batch-quartz/src/main/java/com/spring/infra/security/filter/JwtAuthenticationFilter.java +++ b/batch-quartz/src/main/java/com/spring/infra/security/filter/JwtAuthenticationFilter.java @@ -1,6 +1,7 @@ package com.spring.infra.security.filter; import java.io.IOException; +import java.util.List; import org.springframework.lang.NonNull; import org.springframework.security.core.Authentication; @@ -20,11 +21,18 @@ import lombok.RequiredArgsConstructor; public final class JwtAuthenticationFilter extends OncePerRequestFilter { private final JwtTokenService jwtTokenService; + private final List permitAllUrls; @Override protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain) throws ServletException, IOException { + String requestURI = request.getRequestURI(); + if (permitAllUrls.stream().anyMatch(requestURI::startsWith)) { + filterChain.doFilter(request, response); + return; + } + String accessToken = jwtTokenService.resolveTokenFromCookie(request, JwtTokenRule.ACCESS_PREFIX); if (jwtTokenService.validateAccessToken(accessToken)) { setAuthenticationToContext(accessToken); diff --git a/batch-quartz/src/main/java/com/spring/infra/security/jwt/JwtTokenService.java b/batch-quartz/src/main/java/com/spring/infra/security/jwt/JwtTokenService.java index 4ec3cf1..8d4ca25 100644 --- a/batch-quartz/src/main/java/com/spring/infra/security/jwt/JwtTokenService.java +++ b/batch-quartz/src/main/java/com/spring/infra/security/jwt/JwtTokenService.java @@ -21,11 +21,10 @@ public class JwtTokenService { private final JwtTokenUtil jwtTokenUtil; private final JwtTokenGenerator jwtTokenGenerator; private final UserPrincipalService userPrincipalService; - - private final Key ACCESS_SECRET_KEY; - private final Key REFRESH_SECRET_KEY; - private final long ACCESS_EXPIRATION; - private final long REFRESH_EXPIRATION; + private final Key accessSecretKey; + private final Key refreshSecretKey; + private final long accessExpiration; + private final long refreshExpiration; public JwtTokenService( JwtTokenUtil jwtTokenUtil, @@ -36,22 +35,22 @@ public class JwtTokenService { this.jwtTokenUtil = jwtTokenUtil; this.jwtTokenGenerator = jwtTokenGenerator; this.userPrincipalService = userPrincipalService; - this.ACCESS_SECRET_KEY = jwtTokenUtil.getSigningKey(jwtProperties.getAccessToken().getSecret()); - this.REFRESH_SECRET_KEY = jwtTokenUtil.getSigningKey(jwtProperties.getRefreshToken().getSecret()); - this.ACCESS_EXPIRATION = jwtProperties.getAccessToken().getExpiration(); - this.REFRESH_EXPIRATION = jwtProperties.getRefreshToken().getExpiration(); + this.accessSecretKey = jwtTokenUtil.getSigningKey(jwtProperties.getAccessToken().getSecret()); + this.refreshSecretKey = jwtTokenUtil.getSigningKey(jwtProperties.getRefreshToken().getSecret()); + this.accessExpiration = jwtProperties.getAccessToken().getExpiration(); + this.refreshExpiration = jwtProperties.getRefreshToken().getExpiration(); } public String generateAccessToken(HttpServletResponse response, Authentication authentication) { String accessToken = jwtTokenGenerator.generateAccessToken(authentication); - ResponseCookie cookie = setTokenToCookie(JwtTokenRule.ACCESS_PREFIX.getValue(), accessToken, ACCESS_EXPIRATION / 1000); + ResponseCookie cookie = setTokenToCookie(JwtTokenRule.ACCESS_PREFIX.getValue(), accessToken, accessExpiration / 1000); response.addHeader(JwtTokenRule.JWT_ISSUE_HEADER.getValue(), cookie.toString()); return accessToken; } public String generateRefreshToken(HttpServletResponse response, Authentication authentication) { String refreshToken = jwtTokenGenerator.generateRefreshToken(authentication); - ResponseCookie cookie = setTokenToCookie(JwtTokenRule.REFRESH_PREFIX.getValue(), refreshToken, REFRESH_EXPIRATION / 1000); + ResponseCookie cookie = setTokenToCookie(JwtTokenRule.REFRESH_PREFIX.getValue(), refreshToken, refreshExpiration / 1000); response.addHeader(JwtTokenRule.JWT_ISSUE_HEADER.getValue(), cookie.toString()); return refreshToken; } @@ -67,23 +66,23 @@ public class JwtTokenService { } public boolean validateAccessToken(String token) { - return jwtTokenUtil.getTokenStatus(token, ACCESS_SECRET_KEY) == JwtTokenStatus.AUTHENTICATED; + return jwtTokenUtil.getTokenStatus(token, accessSecretKey) == JwtTokenStatus.AUTHENTICATED; } public boolean validateRefreshToken(String token) { - return jwtTokenUtil.getTokenStatus(token, REFRESH_SECRET_KEY) == JwtTokenStatus.AUTHENTICATED; + return jwtTokenUtil.getTokenStatus(token, refreshSecretKey) == JwtTokenStatus.AUTHENTICATED; } public String resolveTokenFromCookie(HttpServletRequest request, JwtTokenRule tokenPrefix) { Cookie[] cookies = request.getCookies(); if (cookies == null) { - throw new RuntimeException("JWT_TOKEN_NOT_FOUND"); + throw new IllegalStateException("JWT_TOKEN_NOT_FOUND"); } return jwtTokenUtil.resolveTokenFromCookie(cookies, tokenPrefix); } public Authentication getAuthentication(String token) { - UserDetails principal = userPrincipalService.loadUserByUsername(getUserPk(token, ACCESS_SECRET_KEY)); + UserDetails principal = userPrincipalService.loadUserByUsername(getUserPk(token, accessSecretKey)); return new UsernamePasswordAuthenticationToken(principal, "", principal.getAuthorities()); } diff --git a/batch-quartz/src/main/resources/application.yml b/batch-quartz/src/main/resources/application.yml index ee24177..df03105 100644 --- a/batch-quartz/src/main/resources/application.yml +++ b/batch-quartz/src/main/resources/application.yml @@ -45,11 +45,11 @@ spring: batch: jdbc: - initialize-schema: never + initialize-schema: always quartz: jdbc: - initialize-schema: never + initialize-schema: always wait-for-jobs-to-complete-on-shutdown: true job-store-type: jdbc properties: