天天看點

SpringBoot - 異步任務、定時任務(Scheduled和Quartz)、郵件任務

異步任務

在Java應用中,絕大多數情況下都是通過同步的方式來實作互動處理的;但是在處理與第三方系統互動的時候,容易造成響應遲緩的情況,之前大部分都是使用多線程來完成此類任務,其實,在Spring 3.x之後,就已經内置了

@Async

來完美解決這個問題。

注解使用

在SpringBoot裡,需要給啟動類添加

@EnableAsync

來開啟異步注解。

使用

@Async

異步注解:

@Service
public class AsyncService {
    @Async       // 該注解表明這是一個異步任務
    public void hello(){
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("處理資料中...");
    }
}
           

定時任務

一、@Scheduled

項目開發中經常需要執行一些

定時任務

,比如需要在每天淩晨時候,分析一次前一天的日志資訊,統計前一天的商品銷量等。Spring為我們提供了異步執行任務排程的方式,提供

TaskExecutor

TaskScheduler

接口。

要使用同步任務,首先需要了解SpringTask以及Cron表達式

SpringBoot - 異步任務、定時任務(Scheduled和Quartz)、郵件任務
SpringBoot - 異步任務、定時任務(Scheduled和Quartz)、郵件任務

注解使用

在SpringBoot裡,需要給啟動類添加

@EnableScheduling

來開啟定時任務注解。

使用

@Scheduled

定時任務注解:

@Service
public class ScheduleService {
    /**
     * Cron表達式
     */
    @Scheduled(cron = "0/4 * * * * MON-SAT")  // 每4秒執行一次
    public void hello(){
        System.out.println("hello...");
    }
    
    /**
     * initialDelay:首次執行任務的延遲
     * fixedRate:目前任務開始執行2000ms之後開啟另一個定時任務
     */
    @Scheduled(initialDelay = 1000,fixedRate = 2000)
    public void world(){
   		System.out.println("world...");
    }
   
    /**
     * fixedDelay:目前任務執行結束1000ms之後開啟另一個任務
     */
    @Sheduled(fixedDelay = 1000)
    public void test(){
    	System.out.println("text...");
    }
}
           

定時任務+異步任務

實作定時任務不阻塞。預設定時任務是阻塞的。

設定線程池大小

# 線程池 核心大小-5,最大大小-50
spring.task.execution.pool.core-size=5
spring.task.execution.pool.max-size=50
           

代碼示例

@EnableAsync
@EnableScheduling
@Component
@Slf4j
public class HelloSchedule {
    /**
     * 1、Spring中6位組成,不允許7位的年
     * 2、在周幾的位置,1-7表示周一到周日: MON-SUN
     * 3、定時任務不應該阻塞:預設是阻塞的
     *    解決方案:
     *      1、可以讓業務運作以異步的方式,自己送出到線程池
     *          CompletableFuture.runAsync(() -> {
     *              xxxService.hello();
     *          },executor);
     *      2、支援定時任務線程池:設定 TaskSchedulingProperties,不推薦,有時候不好使
     *          spring.task.scheduling.pool.size=5
     *      3、讓定時任務異步執行
     *          異步任務:
     *              1、給類加上@EnableAsync注解
     *              2、給方法加上@Async注解
     *      解決:異步+定時任務來完成定時任務不阻塞的功能
     */
    @Scheduled(cron = "* * * ? * 5")
    @Async
    public void hello() throws InterruptedException {
        log.info("hello");
        Thread.sleep(3000);
    }
}
           

二、Quartz

Quartz 是一個功能豐富的開源作業排程庫,它由 Java 寫成,可以內建在任何 Java 應用程式中,

包括 Java SE 和 Java EE 等。使用 Quartz 可以建立簡單或者複雜的執行計劃,它支援資料庫、叢集、插件以及郵件,并且支援 cron 表達式,具有極高的靈活性。

1、引入依賴
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
           
2、建立兩個任務

①普通JavaBean

@Component
public class MyFirstJob {
    public void firstJob(){
        System.out.println("MyFirstJob:firstJob-" + new Date());
    }
}
           

②繼承QuartzJobBean

public class MySecondJob extends QuartzJobBean{
    private String name;

    public void setName(String name){
        this.name = name;
    }

    /**
     * 任務被調用時使用
     */
    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext){
        System.out.println("SecondJob:" + name + "-" + new Date());
    }
}

           
3、配置任務
@Configuration
public class QuartzConfig {
    /**
     * JobDetail配置方式一
     * 該方式隻需要指定:執行個體名、方法名
     * 缺點:無法傳遞參數
     */
    @Bean
    public MethodInvokingJobDetailFactoryBean jobDetail1(){
        MethodInvokingJobDetailFactoryBean bean = new MethodInvokingJobDetailFactoryBean();
        bean.setTargetBeanName("myFirstJob");
        bean.setTargetMethod("firstJob");
        return bean;
    }

    /**
     * JobDetail配置方式二
     * 該方式隻需要指定:JobClass - 即繼承QuartzJobBean的類
     * 優點:可以通過jobDataMap傳遞參數,key與Job中的屬性名一緻即可,且Job中的屬性要提供set方法
     */
    @Bean
    public JobDetailFactoryBean jobDetail2(){
        JobDetailFactoryBean bean = new JobDetailFactoryBean();
        bean.setJobClass(MySecondJob.class);
        JobDataMap jobDataMap = new JobDataMap();
        jobDataMap.put("name","LCY");
        bean.setJobDataMap(jobDataMap);
        bean.setDurability(true);
        return bean;
    }

    /**
     * Trigger常見實作方式一
     */
    @Bean
    public SimpleTriggerFactoryBean simpleTrigger(){
        SimpleTriggerFactoryBean bean = new SimpleTriggerFactoryBean();
        bean.setJobDetail(jobDetail1().getObject());
        // 任務循環次數
        bean.setRepeatCount(3);
        // 任務啟動延遲時間
        bean.setStartDelay(1000);
        // 任務時間間隔
        bean.setRepeatInterval(2000);
        return bean;
    }

    /**
     * Trigger常見實作方式二
     */
    @Bean
    public CronTriggerFactoryBean cronTrigger(){
        CronTriggerFactoryBean bean = new CronTriggerFactoryBean();
        bean.setJobDetail(jobDetail2().getObject());
        // Corn表達式 - 每秒執行一次
        bean.setCronExpression("* * * * * ?");
        return bean;
    }

    /**
     * 建立SchedulerFactory
     */
    @Bean
    public SchedulerFactoryBean schedulerFactory(){
        SchedulerFactoryBean bean = new SchedulerFactoryBean();
        // 配置Trigger
        SimpleTrigger simpleTrigger = simpleTrigger().getObject();
        CronTrigger cronTrigger = cronTrigger().getObject();
        // Trigger多參數
        bean.setTriggers(simpleTrigger,cronTrigger);
        return bean;
    }

}
           
4、測試結果
SpringBoot - 異步任務、定時任務(Scheduled和Quartz)、郵件任務

郵件任務

郵件任務在項目中也比較常見,比如使用者注冊,我們可以通過郵件的方式确認注冊資訊(驗證碼),注冊成功了,發送一些有關的資訊等等。

原理

[email protected]

要給

[email protected]

發送郵件,它們不是直接互動的。而是lcy要登入自己的郵箱伺服器,登進來以後以這個賬戶為名,給jyqc發郵件。而給jyqc發郵件,也是qq郵箱伺服器發給163郵箱伺服器,163郵箱伺服器再發給jyqc的。

SpringBoot - 異步任務、定時任務(Scheduled和Quartz)、郵件任務

一、依賴引入及自動配置

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

自動配置

SpringBoot - 異步任務、定時任務(Scheduled和Quartz)、郵件任務

配置檔案内容

SpringBoot - 異步任務、定時任務(Scheduled和Quartz)、郵件任務

二、開啟郵箱服務

QQ郵箱為例

,需要開啟這些服務:

SpringBoot - 異步任務、定時任務(Scheduled和Quartz)、郵件任務

然後我們就可以點選生成授權碼,在

yml

配置檔案中使用。

三、配置yml

主要需要配置郵箱的

賬号

密碼(授權碼)

郵箱主機位址

spring:
  mail:
    username: [email protected]    # 郵箱
    password: vzydizxcystfkwefi    # 授權碼
    host: smtp.qq.com             # QQ郵箱主機位址
    default-encoding: utf-8       # 編碼,預設UTF-8
    properties:
      mail:
        smtp:
          ssl:
            enable: true          # 安全的ssl連結
           

四、簡單郵件發送

注入

JavaMailSenderImpl

@Autowired
private JavaMailSenderImpl mailSender;

@Test
public void test(){
	// 簡單郵件資訊對象
	SimpleMailMessage message = new SimpleMailMessage();
	// 郵件标題
	message.setSubject("尋寶遊戲注冊驗證碼:");
	// 郵件内容
	message.setText("驗證碼:123456");
	// 郵件接收方
	message.setTo("[email protected]");
	// 郵件發送方
	message.setFrom("[email protected]");
	// 發送
	mailSender.send(message);
}
           
SpringBoot - 異步任務、定時任務(Scheduled和Quartz)、郵件任務

五、複雜郵件發送

@Test
public void test1(){
	try {
		// 複雜的消息郵件對象
		MimeMessage mimeMessage = mailSender.createMimeMessage();
		// 參數2:是否上傳檔案
		MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
		// 郵件标題
		helper.setSubject("尋寶遊戲注冊");
		// 設定内容 - 參數2:是否使用html格式
		helper.setText("<em style='color:red'>注冊成功!請閱讀附件!</em>",true);
		// 郵件接收方
		helper.setTo("[email protected]");
		// 郵件發送方
		helper.setFrom("[email protected]");

		//上傳檔案
		helper.addAttachment("1.jpg",new File("D:\\1.jpg"));
		helper.addAttachment("2.jpg",new File("D:\\2.jpg"));
		// 發送
		mailSender.send(mimeMessage);
	} catch (MessagingException e) {
		e.printStackTrace();
	}
}
           
SpringBoot - 異步任務、定時任務(Scheduled和Quartz)、郵件任務

繼續閱讀