【从年初的一无所有,到年终的身无分文,唉,我这不忘初心。。。】
Quartz是一个完全由Java编写的开源任务调度的框架,通过触发器设置作业定时运行规则,控制作业的运行时间。Quartz定时器作用很多,比如:定时发送信息、定时生成报表等等。
Quartz框架主要核心组件包括调度器、触发器、作业。调度器作为作业的总指挥,触发器作为作业的操作者,作业为应用的功能模块。其关系如图9-1所示:
图9-1 redis断点调试界面
Job是一个接口,该接口只有一个方法execute,被调度的作业(类)需实现该接口中execute()方法,JobExecutionContext类提供了调度上下文的各种信息。每次执行该Job均重新创建一个Job实例。Job的源码如下所示:
public interface Job {
void execute(JobExecutionContext var1) throws JobExecutionException;
}
Quartz在每次执行Job时,都重新创建一个Job实例,所以它不直接接受一个Job的实例,相反它接收一个Job实现类,以便运行时通过newInstance()的反射机制实例化Job。因此需要通过一个类来描述Job的实现类及其它相关的静态信息,如Job名字、描述、关联监听器等信息,JobDetail承担了这一角色。JobDetail 用来保存我们作业的详细信息。一个JobDetail可以有多个Trigger,但是一个Trigger只能对应一个JobDetail
Trigger触发器描述触发Job执行规则。主要有SimpleTrigger和 CronTrigger这两个子类。当仅需触发一次或者以固定时间间隔周期执行,SimpleTrigger是最适合的选择;而CronTrigger则可以通过Cron表达式定义出各种复杂时间规则的调度方案:如每早晨9:00执行,周一、周三、周五下午5:00执行等。Cron表达式定义如下:
CronTrigger配置格式:
格式: [秒] [分] [小时] [日] [月] [周] [年]
0 0 12 * * ? 每天12点触发
0 15 10 ? * * 每天10点15分触发
0 15 10 * * ? 每天10点15分触发
0 15 10 * * ? * 每天10点15分触发
0 15 10 * * ? 2005 2005年每天10点15分触发
0 * 14 * * ? 每天下午的 2点到2点59分每分触发
0 0/5 14 * * ? 每天下午的 2点到2点59分(整点开始,每隔5分触发)
0 0/5 14,18 * * ? 每天下午的 18点到18点59分(整点开始,每隔5分触发)
0 0-5 14 * * ? 每天下午的 2点到2点05分每分触发
0 10,44 14 ? 3 WED 3月分每周三下午的 2点10分和2点44分触发
0 15 10 ? * MON-FRI 从周一到周五每天上午的10点15分触发
0 15 10 15 * ? 每月15号上午10点15分触发
0 15 10 L * ? 每月最后一天的10点15分触发
0 15 10 ? * 6L 每月最后一周的星期五的10点15分触发
0 15 10 ? * 6L 2002-2005 从2002年到2005年每月最后一周的星期五的10点15分触发
0 15 10 ? * 6#3 每月的第三周的星期五开始触发
0 0 12 1/5 * ? 每月的第一个中午开始每隔5天触发一次
0 11 11 11 11 ? 每年的11月11号 11点11分触发(光棍节)
Scheduler负责管理Quartz的运行环境,Quartz它是基于多线程架构的,它启动的时候会初始化一套线程,这套线程会用来执行一些预置的作业。Trigger和JobDetail可以注册到Scheduler中。Scheduler可以将Trigger绑定到某一JobDetail中,这样当Trigger触发时,对应的Job就被执行。Scheduler拥有一个SchedulerContext,它类似于ServletContext,保存着Scheduler上下文信息,Job和Trigger都可以访问SchedulerContext内的信息。Scheduler使用一个线程池作为任务运行的基础设施,任务通过共享线程池中的线程提高运行效率。
在Spring Boot中集成Quartz,首先需要在pom.xml文件中引入所需的依赖,具体代码如下:
org.quartz-scheduler
quartz
2.2.3
创建定时器的方法有两种,1)使用XML配置文件的方式。2)使用注解的方式。注解的方式不需要任何配置文件,简单高效,这两种方式都会讲到。我们先来讲第一种方式,也就是配置文件的方式。首先,我们需要在/src/main/resources目录下新建配置文件spring-mvc.xml,具体代码如下:
< import>标签:利用import标签导入定时器的配置文件,该标签可以根据具体业务分离配置文件。然后,我们在/src/main/resources目录下新建spring-quartz.xml配置文件,具体代码如下:
run
0/10 * * * * ?
在spring-quartz.xml配置文件中,我们分别定义了Job、JobDetail、Trigger、以及Scheduler。并配置了它们之间的关系。
定时器的依赖以及配置文件开发完成之后,我们在/src/main/java/com.example.demo.quartz目录下新建定时器类TestTask.java。具体代码如下:
/**
* 描述:定时器类
* @author Ay
* @date 2017/11/18
*/
public class TestTask {
//日志对象
private static final Logger logger = LogManager.getLogger(TestTask.class);
public void run() {
logger.info("定时器运行了!!!");
}
}
如果我们使用第二种创建定时器的方法,相对就简单了,只需要创建一个定时器类,加上相关的注解就搞定了。比如,我们可以在/src/main/java/com.example.demo.quartz目录下创建SendMailQuartz定时器类,具体代码如下:
/**
* 描述:定时器类
* @author Ay
* @date 2017/11/18
*/
@Component
@Configurable
@EnableScheduling
public class SendMailQuartz {
//日志对象
private static final Logger logger = LogManager.getLogger(SendMailQuartz.class);
//每5秒执行一次
@Scheduled(cron = "*/5 * * * * * ")
public void reportCurrentByCron(){
logger.info("定时器运行了!!!");
}
}
@Configurable:加上此注解的类相当于XML配置文件,可以被Spring Boot扫描初始化。
@EnableScheduling:通过在配置类注解@EnableScheduling来开启对计划任务的支持,然后在要执行计划任务的方法上注解@Scheduled,声明这是一个计划任务。
@Scheduled:注解为定时任务,cron表达式里写执行的时机。
9.1.3节中,我们已经开发好spring-mvc.xml配置文件,但是想让Spring Boot扫描到该配置文件,还需要在入口类MySpringBootApplication中添加@ImportResource注解,具体代码如下:
@SpringBootApplication
@ServletComponentScan
@ImportResource(locations={"classpath:spring-mvc.xml"})
public class MySpringBootApplication {
//省略代码
}
@ImportResource:导入资源配置文件,让Spring Boot可以读取到,类似于XML配置文件中的标签。
代码开发完成之后,我们重新启动项目,在Intellij IDEA控制台中可以看到如图9-2所示的信息,证明在Spring Boot中整合Quartz定时器成功。
邮件服务在互联网早期就已经出现,如今已成为人们互联网生活中必不可少的一项服务。邮件发送与接收的过程如下:
1)发件人使用SMTP协议传输邮件到邮件服务器A;
2)邮件服务器A根据邮件中指定的接收者,投送邮件至相应的邮件服务器B;
3)收件人使用POP3协议从邮件服务器B接收邮件。
SMTP(Simple Mail Transfer Protocol)是电子邮件(Email)传输的互联网标准,定义在RFC5321,默认使用端口25;
POP3(Post Office Protocol - Version 3)主要用于支持使用客户端远程管理在服务器上的电子邮件。定义在RFC 1939,为POP协议的第三版(最新版)。
这两个协议均属于TCP/IP协议族的应用层协议,运行在TCP层之上。
发送邮件的需求比较常见,如找回密码、事件通知、向用户发送广告邮件等。SUN公司提供给广大Java开发人员的一款邮件发送和接收的开源类库JavaMail,支持常用的邮件协议,如:SMTP、POP3、IMAP等。开发人员使用JavaMail编写邮件程序时,不再需要考虑底层的通讯细节如:Socket,而是关注逻辑层面。JavaMail可以发送各种复杂MIME格式的邮件内容,注意JavaMail仅支持JDK4及以上版本。虽然JavaMail是JDK的API但它并没有直接加入JDK中,所以我们需要另外添加依赖。
Spring提供了非常好用的JavaMailSender接口实现邮件发送。在Spring Boot的Starter模块中已为此提供了自动化配置。
在Spring Boot中集成Mail,首先需要在pom.xml文件中引入所需的依赖,具体代码如下:
org.springframework.boot
spring-boot-starter-mail
在pom文件引入Mail所需的依赖之后,我们需要在application.properties文件中添加如下的配置信息:
###mail邮件配置
###邮箱主机
spring.mail.host=smtp.163.com
###用户名
spring.mail.username=ay_test@163.com
###设置的授权码
spring.mail.password=ay12345
###默认编码
spring.mail.default-encoding=UTF-8
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
在Spring Boot中添加完依赖和配置之后,我们在项目的目录/src/main/java/com.example.demo.mail下新建邮件服务接口类SendJunkMailService,具体代码如下:
/**
* 描述:发送用户邮件服务
* @author Ay
* @date 2017/11/19
*/
public interface SendJunkMailService {
boolean sendJunkMail(List ayUser);
}
然后我们继续在项目的目录/src/main/java/com.example.demo.mail.impl下新建接口类的实现类SendJunkMailServiceImpl.java,具体代码如下:
/**
* 描述:发送用户邮件服务
* @author Ay
* @date 2017/11/19
*/
@Service
public class SendJunkMailServiceImpl implements SendJunkMailService {
@Autowired
JavaMailSender mailSender;
@Resource
private AyUserService ayUserService;
@Value("${spring.mail.username}")
private String from;
public static final Logger logger =
LogManager.getLogger(SendJunkMailServiceImpl.class);
@Override
public boolean sendJunkMail(List ayUserList) {
try{
if(ayUserList == null || ayUserList.size() <= 0 ) return Boolean.FALSE;
for(AyUser ayUser: ayUserList){
MimeMessage mimeMessage = this.mailSender.createMimeMessage();
MimeMessageHelper message = new MimeMessageHelper(mimeMessage);
//邮件发送方
message.setFrom(from);
//邮件主题
message.setSubject("地瓜今日特卖");
//邮件接收方
message.setTo("al_test@163.com");
//邮件内容
message.setText(ayUser.getName() +" ,你知道么?厦门地瓜今日特卖,一斤只要9元");
//发送邮件
this.mailSender.send(mimeMessage);
}
}catch(Exception ex){
logger.error("sendJunkMail error and ayUser=%s", ayUserList, ex);
return Boolean.FALSE;
}
return Boolean.TRUE;
}
}
@Value:可以将application.properties配置文件中的配置设置到属性中。如上面代码中,会将spring.mail.username的值huangwenyi10@163.com设置给from属性。
JavaMailSender:邮件发送接口。在Spring Boot的Starter模块中已为此提供了自动化配置。我们只需要通过注解@Autowired注入进来,即可使用。
在9.1.4节中,我们已经开发了SendMailQuartz定时器类,现在我们重新修改该类,让定时器类能够每隔一段时间,给数据库的用户发送广告邮件,SendMailQuartz类具体的修改如下:
/**
* 描述:定时器类
* @author Ay
* @date 2017/11/18
*/
@Component
@Configurable
@EnableScheduling
public class SendMailQuartz {
//日志对象
private static final Logger logger = LogManager.getLogger(SendMailQuartz.class);
@Resource
private SendJunkMailService sendJunkMailService;
@Resource
private AyUserService ayUserService;
//每5秒执行一次
@Scheduled(cron = "*/5 * * * * * ")
public void reportCurrentByCron(){
List userList = ayUserService.findAll();
if (userList == null || userList.size() <= 0) return;
//发送邮件
sendJunkMailService.sendJunkMail(userList);
logger.info("定时器运行了!!!");
}
}
代码全部开发完成之后,我们重新启动项目,发送邮件定时器类SendMailQuartz每隔5秒(真实项目会设置比较长,比如1天,2天等)会查询数据库表ay_test中的所有用户,并发送广告邮件给对应的用户。我们登陆al_test@163.com邮箱,便可以查看到如图9-1、9-2所示的信息。
来自《梳毛、八卦及语言的进化》
一天,我发现,一只黑蜘蛛在后院的两檐之间结了一张很大的网。难道蜘蛛会飞?要不,从这个檐头到那个檐头,中间有一丈余宽,第一根线是怎么拉过去的?后来,我发现蜘蛛走了许多弯路。从一个檐头起,打结,顺墙而下,一步一步向前爬,小心翼翼,翘起尾部,不让丝沾到地面的沙石或别的物体上,走过空地,再爬上对面的檐头,高度差不多了,再把丝收紧,以后也是如此。
【蜘蛛不会飞翔,但它能够把网凌结在半空中。它是勤奋、敏感、沉默而坚韧的昆虫,它的网制得精巧而规矩,八卦形地张开,仿佛得到神助。这样的成绩,使人不由想起那些沉默寡言的人和一些深藏不露的智者。于是,我记住了蜘蛛不会飞翔,但它照样把网结在空中。奇迹是执着者造成的。】
无
如果有带给你一丝丝小快乐,就让快乐继续传递下去,欢迎鼓励,点赞、顶、欢迎留下宝贵的意见、多谢支持!