Spring Boot微服务项目实战(第2版)学习笔记-第9章Quartz定时器和发送Email

本章主要介绍在Spring Boot中使用XML配置和Java注解两种方式定义和使用Quartz定时器,以及如何在Spring Boot中通过JavaMailSender接口给用户发送广告邮件等内容。

1.使用Quartz定时器

1.1 Quartz概述

Quartz是一个完全由Java编写的开源任务调度的框架,通过触发器设置作业定时运行规则,控制作业的运行时间。Quartz定时器作用很多,比如定时发送信息、定时生成报表等。

Quartz框架主要核心组件包括调度器、触发器、作业,调度器作为作业的总指挥触发器作为作业的操作者作业为应用的功能模块,其关系如图所示。

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执行等。

CronTrigger配置格式:(书中有部分内容错误)

格式[秒] [分] [时] [日] [月] [周] [年]
0 0 12 * * ?每天12点触发
0 15 10 ? * *每天10点15分触发
0 15 10 * * ?每天10点15分触发
0 15 10 * * ? *每天10点15分触发
0 15 10 * * ? 20052005年每天10点15分触发
0 * 14 * * ?每天下午的 2点到2点59分每分触发
0 0/5 14 * * ?每天下午的 2点到2点59分(整点开始,每隔5分触发)
0 0/5 14,18 * * ?每天下午的 2点到2点59分(整点开始,每隔5分触发)每天下午的 18点到18点59分(整点开始,每隔5分触发)
0 0-5 14 * * ?每天下午的 2点到2点05分每分触发
0 10,44 14 ? 3 WED3月分每周三下午的 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使用一个线程池作为任务运行的基础设施,任务通过共享线程池中的线程提高运行效率。

1.2 引入依赖

在Spring Boot中集成Quartz,首先需要在pom.xml文件中引入所需的依赖,具体代码如下:

<!-- quartz定时器-->
<dependency>
	<groupId>org.quartz-scheduler</groupId>
	<artifactId>quartz</artifactId>
	<version>2.2.3</version>
</dependency>

1.3 定时器配置文件

创建定时器的方法有两种:①使用XML配置文件的方式;②使用注解的方式。注解的方式不需要任何配置文件且简单高效,这两种方式都会讲到。我们先来讲第一种方式,也就是配置文件的方式。首先,我们需要在/src/main/resources目录下新建配置文件spring-mvc.xml,具体代码如下:

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:task="http://www.springframework.org/schema/task"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context
		http://www.springframework.org/sch/context/spring-context-4.2.xsd
		http://www.springframework.org/schema/mvc
		http://www.springframework.org/schema/mvc/spring-mvc.xsd
		http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop.xsd
		http://www.springframework.org/schema/task
		http://www.springframework.org/schema/task/spring-task.xsd">

	<context:annotation-config/>
	<!--利用import引入定时器的文件-->
	<import resource="spring-quartz.xml"/>
</beans>
  • <import>标签:import标签用于导入定时器的配置文件,该标签可以根据具体业务分离配置文件。

然后,我们在/src/main/resources目录下新建spring-quartz.xml配置文件,具体代码如下:

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
	<!--定义Job对象-->
	<bean id="taskJob" class="com.example.demo.quartz.TestTask"/>
		<!--定义JobDetail对象-->
		<bean id="JobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
		<!--目标taskJob对象-->
		<property name="targetObject">
			<ref bean="taskJob"/>
		</property>
		<!--目标方法-->
		<property name="targetMethod">
			<value>run</value>
		</property>
	</bean>
	<!--调度触发器-->
	<bean id="myTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
		<!--指定使用 jobDetail-->
		<property name="jobDetail">
			<ref bean="jobDetail"/>
		</property>
		<!--定义触发规则,每10秒执行一次-->
		<property name="cronExpression">
			<value>0/10 * * * * ?</value>
		</property>
	</bean>
	<!--调度工厂-->
	<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
		<!--注册触发器,可注册多个-->
		<property name="triggers">
			<list>
				<ref bean="myTrigger"/>
			</list>
		</property>
	</bean>
</beans>

在spring-quartz.xml配置文件中,我们分别定义了Job、JobDetail、Trigger以及Scheduler。并配置了它们之间的关系。

1.4 创建定时器类

定时器的依赖及配置文件开发完成之后,在/src/main/java/com.example.demo.quartz目录下新建定时器类TestTask.java。具体代码如下:

public class TestTask{
	//日志对象
	private static final Logger logger = LogManager.getLogger(TestTest.class);
	public void run(){
		logger.info("定时器运行了!!!");
	}
}

如果使用第二种创建定时器的方法,相对就简单了,只需要创建一个定时器类,加上相关的注解就搞定了。比如,我们可以在/src/main/java/com.example.demo.quartz目录下创建SendMailQuartz定时器类,具体代码如下:

@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配置文件可以被SpringBoot扫描初始化。
  • @EnableScheduling:通过在配置类注解@EnableScheduling来开启对计划任务的支持,然后在要执行计划任务的方法上注解@Scheduled,声明这是一个计划任务。
  • @Scheduled:注解为定时任务,cron表达式里写执行的时机。

1.5 Spring Boot扫描配置文件

已经开发好spring-mvc.xml配置文件,但是想让Spring Boot扫描到该配置文件,还需要在入口类MySpringBootApplication中添加@ImportResource注解,具体代码如下:

@SpringBootApplication
@ServletComponentScan
@ImportResource(locations={"classpath:spring-mvc.xml"})
public class MySpringBootApplication{
	//忽略代码
}
  • @ImportResource:导入资源配置文件,让Spring Boot可以读取到,类似于XML配置文件中的标签。

1.6 测试

代码开发完成之后,重新启动项目,在Intellij IDEA控制台中可以看到如图所示的信息,证明在Spring Boot中整合Quartz定时器成功。
在这里插入图片描述

2.Spring Boot发送Email

2.1 Email介绍

邮件服务在互联网早期就已经出现,如今已成为人们互联网生活中必不可少的一项服务。邮件发送与接收的过程如下:

  1. 发件人使用SMTP协议传输邮件到邮件服务器A。
  2. 邮件服务器A根据邮件中指定的接收者,投送邮件至相应的邮件服务器B。
  3. 收件人使用POP3协议从邮件服务器B接收邮件。

SMTP(Simple Mail Transfer Protocol)是电子邮件(Email)传输的互联网标准,定义在RFC5321,默认使用端口25。

POP3(Post Office Protocol-Version3)主要用于支持使用客户端远程管理在服务器上的电子邮件。定义在RFC1939,为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模块中已为此提供了自动化配置。

2.2 引入依赖

<!--mail start-->
<dependency>
	<groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

2.3 添加Email配置

在pom文件引入Mail所需的依赖之后,需要在application.properties文件中添加如下的配置信息:

### Mail邮件配置
### 邮箱主机
spring.mail.host=smtp.163.com
### 用户名
spring.mail.username=huangwenyi10@163.com
### 设置的授权码
spring.mail.password=自己邮箱密码
### 默认编码
spring.mail.default-encoding=UTE-8
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring mail.properties.mail.smtp.starttls.required=true

2.4 在定时器中发送邮件

在Spring Boot中添加完依赖和配置之后,在项目的/src/main/java/com.example.demo.mail目录下新建邮件服务接口类SendJunkMailService,具体代码如下:

public interface SendJunkMailService{
	boolean sendJunkMail(List<AyUser> ayUser);
}

然后,继续在项目的目录/src/main/java/com.example.demo.mail.impl下新建接口类的实现类SendJunkMailServiceImpl.java,具体代码如下:

@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<AyUser> ayUserList) {
		try {
			if (ayUserList ==null || ayUserList.size()<=0) {
				return Boolean.FALSE;
			} 
			for (AyUser ayUser: ayUserList) {
				MimeMessage mimeMessage = this.mailSender.createMimeMessage();
				MimeMessageHelper message = new MimeMessageHelper(mimiMessage);
				//邮件发送方
				message.setFrom(from);
				//邮件主题
				message.setSubject("地瓜今日特卖");
				//用邮件接收方
				message.setTo("al_test@163.com");
				//邮件内容
				message.setText(ayUser.getName() + "test message");
				//发送邮件
				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注入进来,即可使用。

上一节中已经开发了SendMailQuartz定时器类,现在重新修改该类,让定时器类能够每隔一段时间给数据库的用户发送广告邮件,SendMailQuartz类具体的修改如下

@Component
@Configurable
@EnableScheduling
public class SendMailQuartz {
	//日志对象
	private static final Logger logger = LogManager.getLogger(SendMailQuartz.class);
	//每5秒执行一次
	@Resource
	private SendJunkMailService sendJunkMailService;
	@Resource
	private AyUserService ayUserService;
	
	//每5秒执行一次
	@Scheduled(cron = "*/5 * * * * * ")
	public void reportCurrentByCron() {
		List<AyUser> userList = ayUserService.findAll();
		if (userList == null || userList.size()<=0) return;
		//发送邮件
		sendJunkMailService.sendJunkMail(userList);
		logger.info("定时器运行了!!!");
	}
}

2.5 测试

代码全部开发完成之后,重新启动项目,发送邮件定时器类SendMailQuartz每隔5秒(真实项目会设置比较长,比如1天、2天等)会查询数据库表ay_test中的所有用户,并发送广告邮件给对应的用户。我们登录al_test@163.com邮箱,便可以查看到邮件信息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值