本文共 14025 字,大约阅读时间需要 46 分钟。
模仿学习Spring Boot starter写一个关于Quartz的自动配置的依赖。
自定义starter命名方式:
spring-boot-configuration-processor
是2.x必须引入的包。
4.0.0 com.littlefxc.examples myQuartz-spring-boot-starter 1.0-snapshot jar org.springframework.boot spring-boot-starter-parent 1.5.18.RELEASE 2.3.0 org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-configuration-processor true org.quartz-scheduler quartz ${quartz.version} c3p0 com.mchange HikariCP-java6 com.zaxxer org.springframework spring-context-support org.springframework spring-tx org.springframework.boot spring-boot-starter-jdbc
QuartzAutoConfiguration
构造函数隐式注入
在4.3之前,如果你构造函数中要依赖另外一个bean,你必须显示依赖@Autowired
, 例如: @Servicepublic class FooService { private final FooRepository repository; @Autowired public FooService(FooRepository repository) { this.repository = repository }}
相当常见的用例但是如果你忘记构造函数上的@Autowired注释,容器将抛出一个寻找默认构造函数的异常,除非你在bean定义设置中明确指出autowire模式’constructor’。
因此,从4.3开始,您不再需要在这样的单构造函数场景中指定显式注入注释。对于那些根本不带任何容器注释的类来说,这是特别优雅的,FooService会从beanFactory中查找FooRepository。
同样的,@Configuration
类在4.3之前不支持构造函数注入。
为什么要使用ObjectProvider
?
上文讲过构造函数隐式注入,但其有个缺点那就是强依赖。
Spring Framework 4.3引入了ObjectProvider,它是现有ObjectFactory接口的扩展,具有方便的签名,例如getIfAvailable和getIfUnique,只有在它实际存在时才检索bean(可选支持)或者如果可以确定单个候选者(特别是:主要候选者)在多个匹配的bean的情况下)。它的Spring核心源码见org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency()
** 用到的几个和Starter相关的注解:
@ConditionalOnClass
,当classpath
下发现该类的情况下进行自动配置。@ConditionalOnMissingBean
,当Spring Context中不存在该Bean时。@EnableConfigurationProperties(QuartzProperties.class)
,使@ConfigurationProperties注解生效。@ConfigurationProperties
,主要用来把properties配置文件转化为bean。@AutoConfigureAfter
,自动注入该类在什么类加载之后。@Configuration@ConditionalOnClass({ Scheduler.class, SchedulerFactoryBean.class, PlatformTransactionManager.class})@EnableConfigurationProperties(QuartzProperties.class)@AutoConfigureAfter({ DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})public class QuartzAutoConfiguration { private final static Logger log = LoggerFactory.getLogger(QuartzAutoConfiguration.class); private final Listcustomizers; private final QuartzProperties properties; private final JobDetail[] jobDetails; private final Map calendars; private final Trigger[] triggers; private final ApplicationContext applicationContext; private final DataSource dataSource; private final PlatformTransactionManager transactionManager; public QuartzAutoConfiguration(QuartzProperties properties, ObjectProvider
> customizers, ObjectProvider jobDetails, ObjectProvider
resources/META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.littlefxc.examples.spring.boot.autoconfigure.QuartzAutoConfiguration
@ConfigurationProperties("spring.quartz")public class QuartzProperties { /** * Quartz job store type. */ private JobStoreType jobStoreType = JobStoreType.MEMORY; /** * Additional Quartz Scheduler properties. */ private final Mapproperties = new HashMap<>(); public JobStoreType getJobStoreType() { return this.jobStoreType; } public void setJobStoreType(JobStoreType jobStoreType) { this.jobStoreType = jobStoreType; } public Map getProperties() { return this.properties; }}
public enum JobStoreType { /** * Store jobs in memory. */ MEMORY, /** * Store jobs in the database. */ JDBC}
/** * 模仿了:{@link org.springframework.boot.autoconfigure.quartz.AutowireCapableBeanJobFactory} * * @author fengxuechao * @date 12/19/2018 * @see 注入Spring上下文(applicationContext) */public class AutoSchedulerJobFactory extends SpringBeanJobFactory { private AutowireCapableBeanFactory beanFactory; AutoSchedulerJobFactory(AutowireCapableBeanFactory factory) { beanFactory = factory; } @Override protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception { final Object job = super.createJobInstance(bundle); beanFactory.autowireBean(job); this.beanFactory.initializeBean(job, null); return job; }}
/** * 回调接口,可以由希望在完全初始化之前自定义Quartz SchedulerFactoryBean的bean实现,特别是调整其配置。 * @author fengxuechao */@FunctionalInterfacepublic interface SchedulerFactoryBeanCustomizer { /** * 自定义{@link SchedulerFactoryBean}. * @param schedulerFactoryBean the scheduler to customize */ void customize(SchedulerFactoryBean schedulerFactoryBean);}
新建项目,结构如下图所示:
4.0.0 com.littlefxc.examples test-autoconfigure 1.0-snapshot org.springframework.boot spring-boot-starter-parent 1.5.18.RELEASE 2.3.0 org.springframework.boot spring-boot-starter-web com.littlefxc.examples myQuartz-spring-boot-starter 1.0-snapshot org.quartz-scheduler quartz-jobs ${quartz.version} org.springframework.boot spring-boot-starter-test test org.projectlombok lombok mysql mysql-connector-java com.alibaba druid-spring-boot-starter 1.1.10
logging.level.root=warnlogging.level.com.littlefxc.examples=debug# DataSource Configspring.datasource.url=jdbc:mysql://localhost:3306/learn-quartz?useSSL=falsespring.datasource.username=rootspring.datasource.password=123456spring.datasource.driver-class-name=com.mysql.jdbc.Driverspring.datasource.type=com.alibaba.druid.pool.DruidDataSourcespring.datasource.druid.filters=slf4j,wallspring.datasource.druid.initial-size=1spring.datasource.druid.min-idle=1spring.datasource.druid.max-active=8spring.datasource.druid.max-wait=60000spring.datasource.druid.time-between-eviction-runs-millis=60000spring.datasource.druid.min-evictable-idle-time-millis=300000spring.datasource.druid.test-while-idle=truespring.datasource.druid.test-on-borrow=falsespring.datasource.druid.test-on-return=falsespring.datasource.druid.pool-prepared-statements=truespring.datasource.druid.max-pool-prepared-statement-per-connection-size=20# Quartz Configspring.quartz.job-store-type=jdbcspring.quartz.properties.org.quartz.scheduler.instanceName=schedulerFactoryBeanspring.quartz.properties.org.quartz.scheduler.instanceId=AUTOspring.quartz.properties.org.quartz.scheduler.instanceIdGenerator.class=com.littlefxc.examples.CustomQuartzInstanceIdGeneratorspring.quartz.properties.org.quartz.threadPool.threadCount=20spring.quartz.properties.org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTXspring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegatespring.quartz.properties.org.quartz.jobStore.useProperties=truespring.quartz.properties.org.quartz.jobStore.misfireThreshold=60000spring.quartz.properties.org.quartz.jobStore.tablePrefix=qrtz_spring.quartz.properties.org.quartz.jobStore.isClustered=truespring.quartz.properties.org.quartz.plugin.shutdownHook.class=org.quartz.plugins.management.ShutdownHookPluginspring.quartz.properties.org.quartz.plugin.shutdownHook.cleanShutdown=TRUE
核心代码
@Slf4j@SpringBootApplicationpublic class TestAutoConfigure { public static void main(String[] args) { SpringApplication.run(TestAutoConfigure.class, args); } @Bean public SchedulerFactoryBeanCustomizer dataSourceCustomizer() { return (schedulerFactoryBean) -> { schedulerFactoryBean.setOverwriteExistingJobs(false); schedulerFactoryBean.setWaitForJobsToCompleteOnShutdown(true); schedulerFactoryBean.setStartupDelay(10); }; } /** * JobDetailFactoryBean * * @return */ @Bean public JobDetailFactoryBean jobDetailFactoryBean() { JobDetailFactoryBean bean = new JobDetailFactoryBean(); bean.setName("job-1"); bean.setGroup("job-group-1"); bean.setJobClass(MyJob.class); JobDataMap jobDataMap = new JobDataMap(); jobDataMap.put("hello", "world"); bean.setJobDataMap(jobDataMap); bean.setDurability(true); return bean; } /** * CronTriggerFactoryBean * * @param jobDetail * @return */ @Bean public CronTriggerFactoryBean cronTrigger(JobDetail jobDetail) { CronTriggerFactoryBean bean = new CronTriggerFactoryBean(); bean.setName("cron-1"); bean.setGroup("cron-group-1"); bean.setCronExpression("0/5 * * * * ?"); bean.setJobDetail(jobDetail); return bean; } /** * Job */ @Component public static class MyJob extends QuartzJobBean { @Override protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { JobDetail jobDetail = jobExecutionContext.getJobDetail(); String jobName = jobDetail.getKey().getName(); String jobGroup = jobDetail.getKey().getGroup(); String jobDataMapHello = (String) jobDetail.getJobDataMap().get("hello"); log.info("job.name = {}, job.group = {}, job.dataMap.hello = {}", jobName, jobGroup, jobDataMapHello); } }}
CustomQuartzInstanceIdGenerator
public class CustomQuartzInstanceIdGenerator implements InstanceIdGenerator { @Override public String generateInstanceId() throws SchedulerException { try { return UUID.randomUUID().toString().replaceAll("-", ""); } catch (Exception ex) { throw new SchedulerException("Couldn't generate UUID!", ex); } }}
转载地址:http://hvxzb.baihongyu.com/