**Обмен галантереей недавно организованными личными учебными заметками в книгу с использованием обмена PDF в основном включает в себя основу Java, структуру данных, jvm, многопоточность и т. д. Из-за ограниченного места ниже показано лишь небольшое количество вопросов интервью.
Друзья, которым это нужно, могут нажать, чтобы получить это:Нажмите здесь чтобы получить это. . .Пароль: JJ
**
Scheduled
Он подходит только для обработки простых запланированных задач и не может обрабатывать распределенные запланированные задачи. Преимущества: это запланированная задача, предоставляемая структурой Spring, которую легко разработать и которая имеет высокую эффективность выполнения. А когда запланированных задач слишком много, могут возникнуть такие проблемы, как блокировка, сбой и отложенный запуск.
Запланированная задача по времени — это задача по времени, которая поставляется с весенней версией 3.0. Пакет ресурсов Spring, к которому он принадлежит: spring-context-support. Поэтому, когда вам нужно использовать механизм запланированных задач по времени, вам нужно полагаться на соответствующие ресурсы в проекте, а именно:
<!-- scheduled所属资源为spring-context-support -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
Если вам нужно включить запланированные задачи по времени в приложении spring, вам нужно добавить аннотацию @EnableScheduling в класс запуска, чтобы включить механизм запланированных задач по времени. детали следующим образом:
@SpringBootApplication
@EnableScheduling
public class AppStarter {
public static void main(String[] args) {
SpringApplication.run(AppStarter.class, args);
}
}
Ядром запланированных задач по времени является аннотация @Scheduled.Основным атрибутом этой аннотации является cron, который представляет выражение плана запуска задачи по времени. Формат этого выражения:
@Scheduled(cron="seconds minutes hours day month week")
или
@Scheduled(cron="seconds minutes hours day month week year")
Рекомендуется первая форма выражения, поскольку во многих других технологиях существуют разные механизмы задач синхронизации, а выражения, используемые для установки расписания триггера, являются первыми выражениями cron. Нельзя сказать, что второй тип выражений специфичен для Spring Scheduled, и он также поддерживается лишь несколькими технологиями.
В выражении cron ограничения для каждой позиции следующие:
Звездочка (*): может использоваться во всех полях, указывая каждый момент в соответствующем поле времени, например, * в поле минут, обозначая «каждую минуту»;
Вопросительный знак (?): этот символ используется только в полях даты и недели, обычно он указывается как «бессмысленное значение», что эквивалентно заполнителю;
Знак минус (-): Выразите диапазон, например, используя «10-12» в поле часа, это означает от 10 до 12 часов, то есть 10,11,12;
Запятая (,): Выразите значение списка, например, используя «ПН, СР, ПТ» в поле недели, это означает понедельник, среду и пятницу;
Косая черта (/): x/y выражает последовательность равных шагов, где x — начальное значение, а y — значение возрастающего шага. Если использование 0/15 в поле секунд означает 0, 15, 30 и 45 секунд, а 5/15 в поле минут означает 5, 20, 35, 50, вы также можете использовать */y, что эквивалентно 0/ у;
L: Этот символ используется только в полях даты и недели и означает «последний», но в этих двух полях он имеет разное значение. В поле даты буква L представляет последний день месяца, например, 31 января и 28 февраля в невисокосные годы; если буква L используется в качестве недели, она представляет субботу, что эквивалентно 7. Однако, если L появляется в поле дня недели и ему предшествует значение X, это означает «последние X дней месяца», например, 6L означает последнюю пятницу месяца;
W: Этот символ может появляться только в поле даты.Это модификация начальной даты, указывающая ближайший рабочий день к дате. Например, 15W представляет рабочий день, ближайший к 15-му числу месяца.Если 15-е число месяца — суббота, оно соответствует пятнице 14-го числа, если 15-е число — воскресенье, оно соответствует понедельнику 16-го числа, если 15-е число — вторнику, результат 15 № вторник. Однако следует отметить, что связанная дата сопоставления не может охватывать месяцы.Например, если вы укажете 1W, если 1-е число — суббота, результат будет соответствовать понедельнику 3-го числа, а не последнему дню предыдущего месяца. Строка W может указывать только одну дату, а не диапазон дат;
Комбинация LW: LW можно использовать в комбинации в поле даты, что означает последний рабочий день месяца;
Знак решетки (#): этот символ можно использовать только в поле дня недели для обозначения дня недели месяца. Например, 6#3 представляет собой третью пятницу текущего месяца (6 представляет пятницу, а #3 представляет текущую третью), а 4#5 представляет пятую среду текущего месяца, при условии, что в текущем месяце нет пятой среды. , игнорировать его и не запускать;
C: Этот символ используется только в полях даты и недели, что означает «Календарь». Это означает дату, с которой связан план, или, если дата не связана, она эквивалентна всем датам в календаре. Например, 5C в поле даты эквивалентно первому дню после 5-го числа в календаре. 1С эквивалентно первому дню после воскресенья в поле дня недели.
Выражения Cron нечувствительны к регистру специальных символов, а также нечувствительны к регистру сокращений, обозначающих недели.
Запланированные задачи Запланированные реализованы через пул потоков. Является многопоточным планировщиком. SpringBoot инициализирует пул потоков, размер пула потоков по умолчанию равен 1, который специально используется для выполнения запланированных задач. При запуске каждой запланированной задачи из пула потоков получается поток для выполнения.Если возникает исключение, только поток, выполняющий текущую задачу, имеет исключение, а не поток планирования запланированной задачи. Если текущая запланированная задача еще не была выполнена, когда та же самая запланированная задача снова входит в цикл выполнения, новая запланированная задача не будет запущена. как:
@Scheduled(cron="* * * * * ?")
public void test1(){
Random r = new Random();
/*int i = r.nextInt(100);
if(i % 3 == 0){
throw new RuntimeException("error");
}*/
System.out.println(Thread.currentThread().getName() + " cron=* * * * * ? --- " + new Date());
try{
Thread.sleep(2000);
}catch(Exception e){
e.printStackTrace();
}
}
Как показано в результате (имя потока каждый раз одно и то же, так как предыдущее запланированное задание не выполнено, вызывается задержка последнего задания не на 1 секунду, а на 3 секунды):
pool-1-thread-1 cron=* * * * * ? --- Thu Sep 19 02:23:20 CST 2019
pool-1-thread-1 cron=* * * * * ? --- Thu Sep 19 02:23:23 CST 2019
pool-1-thread-1 cron=* * * * * ? --- Thu Sep 19 02:23:26 CST 2019
pool-1-thread-1 cron=* * * * * ? --- Thu Sep 19 02:23:29 CST 2019
quartz
Quartz — еще один проект с открытым исходным кодом организации OpenSymphony в области планирования заданий, который можно комбинировать с приложениями J2EE и J2SE или использовать отдельно. Quartz можно использовать для создания простых или сложных программ, выполняющих десять, сотни или даже десятки тысяч заданий.
Quartz — это фреймворк планирования заданий с открытым исходным кодом, полностью написанный на java. Пусть вас не пугает термин «планирование работы». Хотя фреймворк Quartz включает в себя множество дополнительных функций, в его простой форме вы обнаружите, что он чрезвычайно прост в использовании!
При разработке приложений, связанных с Quartz, если определены Job (задача), Trigger (триггер) и Scheduler (планировщик), может быть реализована возможность планирования времени. Планировщик является ядром Quartz. Планировщик отвечает за управление средой выполнения приложения Quartz. Планировщик не выполняет всю работу сам по себе, а вызывает логику выполнения задачи в задании в соответствии с критериями срабатывания триггера для завершения. полное планирование запланированных задач.
Задание — каково содержание запланированного задания.
Триггер — когда выполнять задание.
Планировщик — поддерживает среду задач синхронизации и активирует триггеры.
Чтобы применить Quartz в SpringBoot, вам необходимо полагаться на следующие ресурсы:
<dependencies>
<!-- scheduled所属资源为spring-context-support,在Spring中对Quartz的支持,
是集成在spring-context-support包中。
org.springframework.scheduling.quartz
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<!-- Quartz坐标 -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
<!-- Quartz默认需要slf4j支持。springboot中,提供了更高版本的slf4j -->
<exclusions>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- Spring tx 坐标,quartz可以提供分布式定时任务环境。
多个分布点上的Quartz任务,是通过数据库实现任务信息传递的。
通过数据库中的数据,保证一个时间点上,只有一个分布环境执行定时任务。
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency></dependencies>
Активатор добавляет аннотацию @EnableScheduling:
/** *
@EnableScheduling 必要
* 开启定时任务机制。
*/@SpringBootApplication@EnableScheduling
public class AppStarter {
public static void main(String[] args) {
SpringApplication.run(AppStarter.class, args);
}
}
Определите задачу JOB и фиктивный бизнес-объект, вызываемый задачей JOB:
public class SpringBootQuartzJobDemo implements Job {
// 用于模拟任务中的业务对象。也可能是数据访问对象,或其他类型的对象。
@Autowired
private CommonsUtil4Quartz commonsUtil4Quartz;
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("SpringBootQuartzJobDemo : " + new Date());
this.commonsUtil4Quartz.testMethod();
}
}
@Component
public class CommonsUtil4Quartz {
public void testMethod(){
System.out.println("CommonsUtil4Quartz testMethod run...");
}
}
Создайте объекты Trigger и JobDetail и используйте Schedule для настройки задач синхронизации:
/**
* 初始化类
* Quartz环境初始化。
*
*/
@Configuration
public class QuartzConfiguration {
/**
* 创建Job对象。
在Spring环境中,创建一个类型的对象的时候,很多情况下,都是通过FactoryBean来间接创建的。
* 如果有多个Job对象,定义多次方法。
*
* 在JobDetailFactoryBean类型中,
用于创建JobDetail对象的方法,其底层使用的逻辑是:Class.newInstance()
* 也就是说,JobDetail对象不是通过Spring容器管理的。
* 因为Spring容器不管理JobDetail对象,那么Job中需要自动装配的属性,就无法实现自动状态。
如上JOB的第10行会报空指针异常。
*
* 解决方案是:将JobDetail加入到Spring容器中,让Spring容器管理JobDetail对象。
* 需要重写Factory相关代码。实现Spring容器管理JobDetail。
* @return
*/
@Bean
public JobDetailFactoryBean initJobDetailFactoryBean(){
JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
// 提供job类型。
factoryBean.setJobClass(SpringBootQuartzJobDemo.class);
return factoryBean;
}
/**
* 管理Trigger对象
* CronTrigger - 就是Trigger的一个实现类型。
其中用于定义周期时间的是CronSchedulerBuilder
* 实际上,CronTrigger是用于管理一个Cron表达式的类型。
* @param jobDetailFactoryBean - 上一个方法初始化的JobDetailFactoryBean
* @return
*/
@Bean(name="cronTriggerFactoryBean1")
public CronTriggerFactoryBean initCronTriggerFactoryBean( ){
CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean();
JobDetailFactoryBean jobDetailFactoryBean = this.initJobDetailFactoryBean();
factoryBean.setJobDetail(jobDetailFactoryBean.getObject());
factoryBean.setCronExpression("0/3 * * * * ?");
return factoryBean;
}
/**
* 初始化Scheduler
* @param cronTriggerFactoryBean - 上一个方法初始化的CronTriggerFactoryBean
* @return
*/
@Bean
public SchedulerFactoryBean initSchedulerFactoryBean(
CustomJobFactory customJobFactory,
CronTriggerFactoryBean[] cronTriggerFactoryBean){
SchedulerFactoryBean factoryBean = new SchedulerFactoryBean();
CronTrigger[] triggers = new CronTrigger[cronTriggerFactoryBean.length];
for(int i = 0;
i < cronTriggerFactoryBean.length; i++){
triggers[i] = cronTriggerFactoryBean[i].getObject();
}
// 注册触发器,一个Scheduler可以注册若干触发器。
factoryBean.setTriggers(triggers);
// 为Scheduler设置JobDetail的工厂。
可以覆盖掉SpringBoot提供的默认工厂,保证JobDetail中的自动装配有效。
factoryBean.setJobFactory(customJobFactory);
return factoryBean;
}
}
Переопределить JobFactory:
/**
* 重写的工厂对象。
*/
@Component
public class CustomJobFactory extends AdaptableJobFactory {
/**
* AutowireCapableBeanFactory : 简单理解为Spring容器,
是Spring容器Context的一个Bean对象管理工程。
* 可以实现自动装配逻辑,和对象创建逻辑。
* 是SpringIoC容器的一个重要组成部件。
*/
@Autowired
private AutowireCapableBeanFactory autowireCapableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
// 通过父类型中的方法,创建JobDetail对象。
Object obj = super.createJobInstance(bundle);
// 将JobDetail对象加入到Spring容器中,让Spring容器管理,并实现自动装配逻辑。
this.autowireCapableBeanFactory.autowireBean(obj);
return obj;
}
}
Распределенная кварцевая конфигурация
1. Конфигурация зависимостей ресурсов: из-за распределенных причин Quartz предоставляет распределенные пакеты jar обработки и зависимости, связанные с базой данных и соединением.
<dependencies>
<!-- scheduled所属资源为spring-context-support -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<!-- Quartz坐标 -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
<exclusions>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- 是Quartz中提供分布式处理的jar包。-->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.2.1</version>
</dependency>
<!-- Sprng tx 坐标 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<!-- web启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--jdbc -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!--mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- druid数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency></dependencies>
2. Предоставьте конфигурацию, связанную с базой данных:
spring.datasource.url=jdbc:mysql://localhost:3306/quartz?autoReconnect=true&useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driverspring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
spring.datasource.maxWait=600000
spring.datasource.timeBetweenEvictionRunsMillis=600000
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=falseserver.port=8080
3. Предоставьте информацию о конфигурации Quartz, предоставьте информацию о конфигурации базы данных для Quartz, такую как база данных, префикс таблицы и т. д.
# 是否使用properties作为数据存储
org.quartz.jobStore.useProperties=false
# 数据库中的表格命名前缀
org.quartz.jobStore.tablePrefix = QRTZ_
# 是否是一个集群,是不是分布式的任务
org.quartz.jobStore.isClustered = true
# 集群检查周期,单位毫秒。可以自定义缩短时间。
当某一个节点宕机的时候,其他节点等待多久后开始执行任务。
org.quartz.jobStore.clusterCheckinInterval = 5000
# 单位毫秒, 集群中的节点退出后,再次检查进入的时间间隔。
org.quartz.jobStore.misfireThreshold = 60000
# 事务隔离级别
org.quartz.jobStore.txIsolationLevelReadCommitted = true
# 存储的事务管理类型
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
# 使用的Delegate类型
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
# 集群的命名,一个集群要有相同的命名。
org.quartz.scheduler.instanceName = ClusterQuartz
# 节点的命名,可以自定义。AUTO代表自动生成。
org.quartz.scheduler.instanceId= AUTO
# rmi远程协议是否发布
org.quartz.scheduler.rmi.export = false
# rmi远程协议代理是否创建
org.quartz.scheduler.rmi.proxy = false
# 是否使用用户控制的事务环境触发执行job。
org.quartz.scheduler.wrapJobExecutionInUserTransaction = false
4. Инициализировать базу данных
Вы можете самостоятельно найти инструкцию по построению таблицы на официальном сайте (в Quartz-lib) и использовать таблицы-mysql.sql для построения таблицы.
5. Определите класс JOB
Пусковая установка ничем не отличается от обычного кварца, но само определение РАБОТЫ немного отличается:
/**
* 使用Spring提供的Quartz相关Job类型实现Job的定义。
* 父类型QuartzJobBean中,提供了分布式环境中任务的配置定义。
* 保证分布式环境中的任务是有效的。
*/
@PersistJobDataAfterExecution
// 当job执行结束,持久化job信息到数据库
@DisallowConcurrentExecution
// 保证job的唯一性(单例)
public class SpringBootQuartzJobDemo extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext context)
throws JobExecutionException {
System.out.println("SpringBootQuartzJobDemo : " + new Date());
}
}
6. Определение типа QuartzConfiguration
@Configuration
public class QuartzConfiguration {
@Autowired
private DataSource dataSource;
/**
* 创建调度器, 可以省略的。
*
@return
* @throws Exception
*/
@Bean
public Scheduler scheduler() throws Exception {
Scheduler scheduler = schedulerFactoryBean().getScheduler();
scheduler.start();
return scheduler;
}
/**
* 创建调度器工厂bean对象。
* @return
* @throws IOException
*/
@Bean
public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setSchedulerName("Cluster_Scheduler");
factory.setDataSource(dataSource);
factory.setApplicationContextSchedulerContextKey("applicationContext");
// 设置调度器中的线程池。
factory.setTaskExecutor(schedulerThreadPool());
// 设置触发器
factory.setTriggers(trigger().getObject());
// 设置quartz的配置信息
factory.setQuartzProperties(quartzProperties());
return factory;
}
/**
* 读取quartz.properties配置文件的方法。
* @return
* @throws IOException
*/
@Bean
public Properties quartzProperties() throws IOException {
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
// 在quartz.properties中的属性被读取并注入后再初始化对象
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
}
/**
* 创建Job对象的方法。
* @return
*/
@Bean
public JobDetailFactoryBean job() {
JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();
jobDetailFactoryBean.setJobClass(SpringBootQuartzJobDemo.class);
// 是否持久化job内容
jobDetailFactoryBean.setDurability(true);
// 设置是否多次请求尝试任务。
jobDetailFactoryBean.setRequestsRecovery(true);
return jobDetailFactoryBean;
}
/**
* 创建trigger factory bean对象。
* @return
*/
@Bean
public CronTriggerFactoryBean trigger() {
CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
cronTriggerFactoryBean.setJobDetail(job().getObject());
cronTriggerFactoryBean.setCronExpression("0/2 * * * * ?");
return cronTriggerFactoryBean;
}
/**
* 创建一个调度器的线程池。
* @return
*/
@Bean
public Executor schedulerThreadPool() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(15);
executor.setMaxPoolSize(25);
executor.setQueueCapacity(100);
return executor; }
}
Если задание JOB определяет вызывающий бизнес и т.д., JobFactory также необходимо переписать, как, например, приведенный выше обычный кварц, который здесь повторяться не будет.
Личный профиль: Раскованный, любовь к жизни.Культиватор Java (идентификатор общедоступной учетной записи WeChat: Культиватор Java), добро пожаловать, чтобы следовать. Получите 2000G подробных вопросов для интервью 2020 года