基于Quartz实现简单的定时发送邮件
一、什么是Quartz
Quartz 是一个轻量级任务调度框架,只需要做些简单的配置就可以使用;它可以支持持久化的任务存储,即使是任务中断或服务重启后,仍可以继续运行。Quartz既可以做为独立的应用提供服务,也可以和其他应用集成一起使用。
核心概念:
Quartz的类关系图:
注意:Quartz的版本与Spring 的版本有关, Spring 2.x的版本最好用Quartz 1.8.5的,若是 Spring 3.0以上的Quartz 的版本最好用 2.0以上的。
二、基于Sping+Quartz实现简单的JAVA邮件发送
1.创建一个Java(Web)工程
2.实现SimpleMail、MailJob、EmailScheduler类
SimpleMail:
1 package com.quartz.mail; 2 3 import org.apache.commons.mail.EmailException; 4 import org.apache.commons.mail.SimpleEmail; 5 6 import javax.mail.internet.AddressException; 7 import javax.mail.internet.InternetAddress; 8 import java.util.ArrayList; 9 import java.util.Date; 10 import java.util.List; 11 12 /** 13 * Created by xiwu.xxw on 2015/8/8. 14 */ 15 public class SimpleMail { 16 private SimpleEmail mail; 17 18 /** 19 * 初始化一封邮件,暂不支持富媒体和附件 20 * @param receivers 邮件的接收者 21 * @param subject 邮件主题 22 * @param content 邮件内容 23 * @throws EmailException 24 * @throws AddressException 25 */ 26 public SimpleMail(List<String> receivers,String subject,String content) throws EmailException, AddressException { 27 mail=new SimpleEmail(); 28 mail.setCharset("UTF-8"); 29 List<InternetAddress> toList=new ArrayList<InternetAddress>(); 30 for(String receiver: receivers){ 31 toList.add(new InternetAddress(receiver)); 32 } 33 mail.setTo(toList); 34 mail.setSubject(subject); 35 mail.setContent(content, "text/html;charset=utf-8"); 36 } 37 38 /** 39 * 发送邮件 40 * @param from 发送方邮件地址 41 * @param password 发送授权码 42 * @return 43 * @throws EmailException 44 */ 45 public String sendEmail(String from,String password) throws EmailException { 46 mail.setFrom(from); 47 //发送方邮箱权限认证,发送方邮箱须开通SMTP/POP/IMAP功能 48 mail.setAuthentication(from, password); 49 mail.setHostName("smtp." + from.split("@")[1]); 50 mail.setSentDate(new Date()); 51 return mail.send(); 52 } 53 }
MailJob:
1 package com.quartz.job; 2 3 import com.quartz.mail.SimpleMail; 4 import org.quartz.JobDataMap; 5 import org.quartz.JobExecutionContext; 6 import org.quartz.JobExecutionException; 7 import org.springframework.scheduling.quartz.QuartzJobBean; 8 9 import java.util.List; 10 11 /** 12 * Created by xiwu.xxw on 2015/8/8. 13 */ 14 public class MailJob extends QuartzJobBean { 15 /** 16 * 执行Job任务 17 * @param context 18 * @throws JobExecutionException 19 */ 20 @Override 21 protected void executeInternal(JobExecutionContext context) throws JobExecutionException { 22 JobDataMap map=context.getJobDetail().getJobDataMap(); 23 try { 24 SimpleMail mail=new SimpleMail((List<String>) map.get("receivers"),map.getString("subject"),map.getString("content")); 25 String result=mail.sendEmail(map.getString("from"), map.getString("password")); 26 System.out.println(result); 27 } catch (Exception e) { 28 e.printStackTrace(); 29 } 30 } 31 }
EmailScheduler:
1 package com.quartz.scheduler; 2 3 import org.quartz.SchedulerException; 4 import org.quartz.impl.StdScheduler; 5 import org.springframework.context.support.ClassPathXmlApplicationContext; 6 import org.springframework.scheduling.quartz.CronTriggerBean; 7 import org.springframework.scheduling.quartz.JobDetailBean; 8 import org.springframework.scheduling.quartz.SimpleTriggerBean; 9 10 import java.util.ArrayList; 11 import java.util.List; 12 13 /** 14 * Created by xiwu.xxw on 2015/8/8. 15 */ 16 public class EMailScheduler { 17 public static void main(String[] args) throws SchedulerException { 18 //收件人 19 List<String> receivers=new ArrayList<String>(); 20 receivers.add("xxxxx@qq.com"); 21 receivers.add("xxxxx@126.com"); 22 receivers.add("xxxxx@163.com"); 23 24 ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); 25 //邮件JobBean 26 JobDetailBean mailJob= (JobDetailBean) context.getBean("mailJob"); 27 mailJob.setName("mailJob"); 28 mailJob.setGroup("textEmail"); 29 // 指明任务就算没有绑定Trigger仍保留在Quartz的JobStore中 30 //mailJob.setDurability(true); 31 mailJob.getJobDataMap().put("receivers",receivers); 32 mailJob.getJobDataMap().put("subject","基于Quartz实现邮件发送"); 33 mailJob.getJobDataMap().put("content","本程序基于Quartz实现了定时群发邮件的功能,目前只支持文本发送!"); 34 35 36 //发送邮件任务的SimpleTrigger触发器 37 SimpleTriggerBean simpleTrigger= (SimpleTriggerBean) context.getBean("SimpleTrigger"); 38 39 //发送邮件任务调度器 40 StdScheduler scheduler= (StdScheduler) context.getBean("startQuartzTask"); 41 //加入一个任务到Quartz框架中, 并与simpleTrigger关联 42 //Quartz会自动校正与设置simpleTrigger的JobName与JobGroup属性 43 scheduler.scheduleJob(mailJob,simpleTrigger); 44 45 //发送邮件任务的CronTrigger触发器 46 CronTriggerBean croTrigger= (CronTriggerBean) context.getBean("CronTrigger"); 47 //将发送邮件任务的触发器与邮件任务关联并注册到调度器 48 croTrigger.setJobName("mailJob"); 49 croTrigger.setJobGroup("textEmail"); 50 //因为任务已在上一条语句中已加入, 所以不能再使用scheduleJob(JobDetail, Trigger) 51 scheduler.scheduleJob(croTrigger); 52 53 try { 54 //开始调度 55 scheduler.start(); 56 } catch (SchedulerException e) { 57 e.printStackTrace(); 58 } 59 } 60 }
3.配置applicationContext.xml
1 <?xml version="1.0" ?> 2 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" 3 xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" 4 xmlns:tx="http://www.springframework.org/schema/tx" 5 xsi:schemaLocation=" 6 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd 7 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 8 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd 9 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd 10 "> 11 12 <bean id="dataEditor" class="org.springframework.beans.propertyeditors.CustomDateEditor"> 13 <constructor-arg> 14 <bean class="java.text.SimpleDateFormat"> 15 <constructor-arg value="yyyy-MM-dd H:m:s"/> 16 </bean> 17 </constructor-arg> 18 <constructor-arg value="true"/> 19 </bean> 20 21 <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"> 22 <property name="customEditors"> 23 <map> 24 <entry key="java.util.Date"> 25 <ref local="dataEditor"/> 26 </entry> 27 </map> 28 </property> 29 </bean> 30 31 <bean id="mailJob" class="org.springframework.scheduling.quartz.JobDetailBean"> 32 <property name="jobClass"> 33 <value>com.quartz.job.MailJob</value> 34 </property> 35 <property name="jobDataAsMap"> 36 <map> 37 <entry key="from"> 38 <value>xxxxxxx@126.com</value> 39 </entry> 40 <entry key="password"> 41 <value>uebbqvlizrywzhei</value> 42 </entry> 43 </map> 44 </property> 45 </bean> 46 47 <bean id="SimpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> 48 <property name="startDelay"> 49 <value>5000</value> 50 </property> 51 <property name="repeatInterval"> 52 <value>120000</value> 53 </property> 54 <property name="repeatCount"> 55 <value>3</value> 56 </property> 57 </bean> 58 59 <bean id="CronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> 60 <property name="cronExpression"> 61 <value>0 25/2 17 8 8 ? 2015</value> 62 </property> 63 <property name="endTime" value="2015-08-08 17:30:00"/> 64 </bean> 65 66 <bean id="startQuartzTask" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" /> 67 </beans>
4.效果如下
三、注意事项
(1)Job被创建后,可以保存在Scheduler中,与Trigger是独立的,同一个Job可以有多个Trigger;这种松耦合的另一个好处是,当与Scheduler中的Job关联的trigger都过期时,可以配置Job稍后被重新调度,而不用重新定义Job;还有,可以修改或者替换Trigger,而不用重新定义与之关联的Job。
(2)将Job和Trigger注册到Scheduler时,可以为它们设置key,配置其身份属性。Job和Trigger的key(JobKey和TriggerKey)可以用于将Job和Trigger放到不同的分组(group)里,然后基于分组进行操作。同一个分组下的Job或Trigger的名称必须唯一,即一个Job或Trigger的key由名称(name)和分组(group)组成。
(3)在Quartz中,如果实现org.quartz.Job接口,那么这个job是stateless的,job实例的参数不能在多个任务之间共享,做并发,如果实现org.quartz.StatefulJob,这个job是个单例的,job实例的属性可以从当前任务传递到下一个任务,做串行。