前言
简而言之,调度程序是用于调度作业的服务。因此,如果我们希望某些工作在特定的时间或按固定的时间间隔进行,那么计划程序就是我们所需要的。
在AEM中,我们可以通过两种方式创建调度程序-
- Whiteboard Pattern(原始方式)- 在此,我们创建一个Runnable线程来执行我们的任务。这类似于Java Thread概念。
- Scheduler API(第三方API)- 在此,我们使用Apache Commons的Scheduler API执行我们的任务。它使用开源的Quartz库。
AEM中的调度程序
要在AEM中创建调度器,我们将按照以下步骤-
- 创建一个OSGi配置,从用户那里读取调度器的特定值,比如cron表达式、调度器的名称、自定义参数等。
- 创建一个sling调度器。
创建一个OSGi配置
package com.adobe.aem.guides.wknd.core.config;
import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.AttributeType;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
/**
* @author kevin.
* @Title: rhtj.
* @Package com.adobe.aem.guides.wknd.core.config.
* @Description: 这是一个配置类,它获取调度程序要运行的相关属性.
* @date 2020/4/10.
*/
@ObjectClassDefinition(name = "SlingSchedulerConfiguration", description = "Sling scheduler 配置")
public @interface SlingSchedulerConfiguration {
/**
* 调度器的名称.
*
* @return {@link String}
*/
@AttributeDefinition(
name = "Scheduler name",
description = "调度器的名称",
type = AttributeType.STRING)
public String schdulerName() default "自定义Sling调度器配置";
/**
* 调度程序是否启动.
*
* @return {@link Boolean}
*/
@AttributeDefinition(
name = "Enabled",
description = "True代表启动",
type = AttributeType.BOOLEAN)
public boolean enabled() default false;
/**
* Cron表达式.
*
* @return {@link String}
*/
@AttributeDefinition(
name = "Cron Expression",
description = "调度程序使用的Cron表达式",
type = AttributeType.STRING)
public String cronExpression() default "0 * * * * ?";
/**
* 自定义参数.
*
* @return {@link String}
*/
@AttributeDefinition(
name = "Custom Parameter",
description = "自定义参数",
type = AttributeType.STRING)
public String customParameter() default "AEM Scheduler Demo";
}
创建调度程序
现在我们要创建一个sling调度器。创建一个名为CustomScheduler的类。
package com.adobe.aem.guides.wknd.core.schedulers;
import com.adobe.aem.guides.wknd.core.config.SlingSchedulerConfiguration;
import org.apache.sling.commons.scheduler.ScheduleOptions;
import org.apache.sling.commons.scheduler.Scheduler;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Modified;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.metatype.annotations.Designate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author kevin.
* @Title: rhtj.
* @Package com.adobe.aem.guides.wknd.core.schedulers.
* {@link https://osgi.org/javadoc/r6/cmpn/org/osgi/service/component/annotations/package-summary.html}
* @Description: 一个使用OSGi注解的Sling调度器示例.
* @date 2020/4/10.
*/
@Component(immediate = true, service = CustomScheduler.class)
@Designate(ocd = SlingSchedulerConfiguration.class)
public class CustomScheduler implements Runnable {
/**
* Logger.
*/
private static final Logger log = LoggerFactory.getLogger(CustomScheduler.class);
/**
* 要从配置中读取的自定义参数.
*/
private String customParameter;
/**
* 调度程序的Id(基于其名称).
*/
private int schedulerId;
/**
* 调度器实例注入.
*/
@Reference
private Scheduler scheduler;
/**
* 初始化方法.
*
* @param config 调度器配置.
*/
@Activate
protected void activate(SlingSchedulerConfiguration config) {
//1.获取scheduler id
schedulerId = config.schdulerName().hashCode();
//2.获取用户自定义参数.
customParameter = config.customParameter();
}
/**
* 服务组件的修改方法.
*
* @param config 调度器配置.
*/
@Modified
protected void modified(SlingSchedulerConfiguration config) {
//1.删除调度器.
removeScheduler();
//2.更新调度程序id.
schedulerId = config.schdulerName().hashCode();
//3.再次添加调度程序.
addScheduler(config);
}
/**
* 服务组件的停用方法.
*
* @param config 调度器配置.
*/
@Deactivate
protected void deactivate(SlingSchedulerConfiguration config) {
removeScheduler();
}
/**
* 删除调度器.
*/
private void removeScheduler() {
log.info("删除调度器: {}", schedulerId);
scheduler.unschedule(String.valueOf(schedulerId));
}
/**
* 添加调度程序.
*
* @param config 调度器配置.
*/
private void addScheduler(SlingSchedulerConfiguration config) {
//检查调度程序是否已启用.
if (config.enabled()) {
//1.Scheduler将cron表达式作为参数并相应地运行.
ScheduleOptions scheduleOptions = scheduler.EXPR(config.cronExpression());
//2.添加一些属性.
scheduleOptions.name(config.schdulerName());
scheduleOptions.canRunConcurrently(false);
//3.添加调度工作。
scheduler.schedule(this, scheduleOptions);
log.info("Scheduler added");
} else {
log.info("调度器未启用");
}
}
/**
* 执行作业。
*/
@Override
public void run() {
log.info("自定义调度器现在使用传递的自定义参数customParameter运行 {}", customParameter);
}
}
让我们逐步理解代码。
- 首先,我们将类注册为服务并实现Runnable接口。同时,通过使用@Desginate注释,我们将创建的OSGi配置(SlingSchedulerConfiguration)与这个类连接起来。
- 注入org.apache.sling.commons.scheduler.Scheduler依赖项。
- 在activate()方法中,初始化我们所需要的值。
- modified()方法在修改OSGi配置时重新计算调度程序id。
- 在addScheduler()方法中,我们使用调度器API注册调度器。
- run()方法将定义我们的任务。这里我们只是在日志中打印customParameter。
关于代码中的注解的用法和说明请参考官方API:
https://osgi.org/javadoc/r6/cmpn/org/osgi/service/component/annotations/package-summary.html
配置OSGi
-
转到 http://localhost:4502/system/console/configMgr,搜索SlingSchedulerConfiguration,并像下面这样配置它。
-
修改后保存配置.
结果
现在打开你的项目的日志(我的日志文件是- project-wknd.log)并查找跟踪,您将发现如下所示