JAVAEE颠覆者,SpringBoot实战一书学习小记(多线程,计划任务,条件注解@Conditional)

多线程

Spring 通过任务执行器(TaskExecutor)来实现多线程和并发编程。使用ThreadPoolTaskExecutor可实现一个基于线程池的TaskExecutor。而实际开发中任务一般是非阻碍的,即异步的,所以我们要在配置类中通过@EnableAsync开启对异步的支持,并通过在实际执行的Bean的方法中使用@Async注解来声明其是一个异步任务。

示例

首先配置类

package com.cn.sola.config;

import java.util.concurrent.Executor;

import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration
@ComponentScan("com.cn.sola.service")
@EnableAsync//利用此注解开启异步任务支持
public class TaskExecutorConfig implements AsyncConfigurer{

	@Override
	public Executor getAsyncExecutor() {
		//配置类实现AsyncConfigurer 接口 并重写getAsyncExecutor方法并返回一个ThreadPoolTaskExecutor
		//这样我们就获得了一个基于线程池的TaskExecutor
		ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
		
		taskExecutor.setCorePoolSize(5);
		taskExecutor.setMaxPoolSize(10);
		taskExecutor.setQueueCapacity(25);
		taskExecutor.initialize();
		
		return taskExecutor;
	}
	
	@Override
	public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
		// TODO Auto-generated method stub
		return null;
	}
}

任务执行类

package com.cn.sola.service;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

@Service
public class AsyncTaskService {

	@Async//该注表明该方法是个异步方法,如果注解在类级别,则表名该类所有的方法都是异步方
	      //而这里的方法自动被注入使用ThreadPoolTaskExecutor作为TaskExecutor
	public void excuteAsyncTask(Integer i){
		System.out.println("执行异步任务"+i);
	}
	
	@Async
	public void excuteAsyncTaskPlus(Integer i){
		
		System.out.println("执行异步任务+1:"+(i+1));
	}
}

运行

package com.cn.sola;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;

import com.cn.sola.config.TaskExecutorConfig;
import com.cn.sola.service.AsyncTaskService;


@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootShiZhanApplicationTests {

	@Test
	public void contextLoads() {
		
	   AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TaskExecutorConfig.class);
	
	   
	   AsyncTaskService bean = context.getBean(AsyncTaskService.class);
	   
	   
	   for(int i = 0 ; i<10 ; i++){
		   
		   bean.excuteAsyncTask(i);
		   
		   bean.excuteAsyncTaskPlus(i);
	   }
	   
	   context.close();
	}

}

结果是这样的,结果是并非执行而不是顺序执行的

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.0.3.RELEASE)

2018-07-09 10:57:36.981  INFO 8160 --- [           main] c.c.s.SpringBootShiZhanApplicationTests  : Starting SpringBootShiZhanApplicationTests on DESKTOP-LN7MO04 with PID 8160 (started by JAVA in D:\SpringBootWorkSpace\SpringBootShiZhan)
2018-07-09 10:57:36.982  INFO 8160 --- [           main] c.c.s.SpringBootShiZhanApplicationTests  : No active profile set, falling back to default profiles: default
2018-07-09 10:57:37.665  INFO 8160 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'taskExecutorConfig' of type [com.cn.sola.config.TaskExecutorConfig$$EnhancerBySpringCGLIB$$b7273a85] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2018-07-09 10:57:37.669  INFO 8160 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 
2018-07-09 10:57:38.664  INFO 8160 --- [           main] c.c.s.SpringBootShiZhanApplicationTests  : Started SpringBootShiZhanApplicationTests in 1.93 seconds (JVM running for 2.616)
2018-07-09 10:57:38.756  INFO 8160 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@27aae97b: startup date [Mon Jul 09 10:57:38 CST 2018]; root of context hierarchy
2018-07-09 10:57:38.792  INFO 8160 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'taskExecutorConfig' of type [com.cn.sola.config.TaskExecutorConfig$$EnhancerBySpringCGLIB$$b7273a85] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2018-07-09 10:57:38.792  INFO 8160 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 
2018-07-09 10:57:38.810  INFO 8160 --- [           main] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@27aae97b: startup date [Mon Jul 09 10:57:38 CST 2018]; root of context hierarchy
执行异步任务2
执行异步任务+1:3
执行异步任务3
执行异步任务+1:1
执行异步任务4
执行异步任务1
执行异步任务5
执行异步任务+1:6
执行异步任务6
执行异步任务+1:7
执行异步任务7
执行异步任务+1:8
执行异步任务8
执行异步任务+1:9
执行异步任务9
执行异步任务+1:10
执行异步任务0
执行异步任务+1:2
执行异步任务+1:5
执行异步任务+1:4
-------------------------------------------------------------------------------------------------------------------------------

计划任务

从Spring3.1开始,计划任务在Spring中的实现变得异常的简单。首先通过在配置配注解@EnableScheduling来开启对任务的支持,然后再要执行计划任务的方法上声明注解@Scheduled,声明这是一个计划任务。

这段很简单配置好声明个注解就可以了

package com.cn.sola.service;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

@Service
public class ScheduledTaskService {
	
	private static final SimpleDateFormat deteformat = new SimpleDateFormat("HH:mm:ss");

	@Scheduled(fixedRate = 5000)//通过此注解声明该方法是计划任务,使用fixedRate属性每隔固定时间执行
	public void reportCurrentTime(){
		
		System.out.println("每五秒执行一次" + deteformat.format(new Date()));
	}
	@Scheduled(cron = "0 28 11 ? * *") //使用cron属性可以按照指定时间执行,本例指的是每天11点28分执行;cron是unix和类unix(Linux)系统下的定时任务
	public void fixTimeExecution(){
		System.out.println("在指定时间" + deteformat.format(new Date()) + "执行");
	}
}

配置类

package com.cn.sola.config;


import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;


@Configuration
@ComponentScan("com.cn.sola.service")
@EnableScheduling//声明此注解对计划任务的支持
public class TaskSchedulerConfig{
	
}

直接运行即可,那么注解上的方法就会按照注解的时间执行

---------------------------------------------------------------------------------------------------------------------------

条件注解@Conditional

在之前学到,通过活动的profile,我们可以获得不同的Bean,Spring4提供了一个更通用的基于条件的Bean的创建,即使用@Conditional注解。


@Conditional根据满足某一个特定条件创建一个特定的Bean。比方说,当某个jar包在一个类路径下的时候,自动配置一个或多个Bean;或者只有某个Bean被创建才会创建另外一个Bean。总的来说,就是根据特定条件来控制Bean的创建行为,这样我们可以进行一些自动配置。


在SpringBoot中将会大量应用到条件注解,下面的示例将以不用的操作系统作为条件,我们将通过实现Condition接口并重写其Matches方法来构造判断条件,若在Windows系统下运行程序,则输出列表命令为dir;若在linux操作系统下运行程序,则输出列表命令为ls。

首先判断条件定义

windows

package com.cn.sola.bean;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class WindowsCondition implements Condition{

	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		
		return context.getEnvironment().getProperty("os.name").contains("Windows");
	}

}

linux

package com.cn.sola.bean;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class LinuxCondition implements Condition{

	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metdata) {
	
		return context.getEnvironment().getProperty("os.name").contains("Linux");
	}

}

不同系统下的Bean类

接口

package com.cn.sola.service;

public interface ListService {

	public String showListCmd();
}

windows下所要创建的Bean的类

package com.cn.sola.service;

public class WindowListService implements ListService{

	@Override
	public String showListCmd() {
		// TODO Auto-generated method stub
		return "dir";
	}

}

linux下要创建的bean类

package com.cn.sola.service;

public class LinuxService implements ListService{

	@Override
	public String showListCmd() {
		// TODO Auto-generated method stub
		return "ls";
	}

}

配置类

package com.cn.sola.config;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

import com.cn.sola.bean.LinuxCondition;
import com.cn.sola.bean.WindowsCondition;
import com.cn.sola.service.LinuxService;
import com.cn.sola.service.ListService;
import com.cn.sola.service.WindowListService;

@Configuration
public class ConditionConfig{
	
	@Bean
	@Conditional(WindowsCondition.class)//通过注解,符合windows条件则实例化下面的service
	public ListService windowListService(){
		return new WindowListService();
	}
	
	@Bean
	@Conditional(LinuxCondition.class)//通过注解,符合linux条件则实例化下面的service
	public ListService LinuxListService(){
		return new LinuxService();
	}
}

运行类

package com.cn.sola;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;

import com.cn.sola.config.ConditionConfig;
import com.cn.sola.service.LinuxService;
import com.cn.sola.service.ListService;



@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootShiZhanApplicationTests {

	@Test
	public void contextLoads() {
		
	   AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConditionConfig.class);
	
	   ListService listservice = context.getBean(ListService.class);
	   
	   System.out.println(context.getEnvironment().getProperty("os.name")+"系统下的列表命令为:" + listservice.showListCmd());
	   
	   context.close();
	}

}

结果

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.0.3.RELEASE)

2018-07-09 14:54:21.686  INFO 14104 --- [           main] c.c.s.SpringBootShiZhanApplicationTests  : Starting SpringBootShiZhanApplicationTests on DESKTOP-LN7MO04 with PID 14104 (started by JAVA in D:\SpringBootWorkSpace\SpringBootShiZhan)
2018-07-09 14:54:21.687  INFO 14104 --- [           main] c.c.s.SpringBootShiZhanApplicationTests  : No active profile set, falling back to default profiles: default
2018-07-09 14:54:23.480  INFO 14104 --- [           main] c.c.s.SpringBootShiZhanApplicationTests  : Started SpringBootShiZhanApplicationTests in 2.049 seconds (JVM running for 2.786)
2018-07-09 14:54:23.607  INFO 14104 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@67a056f1: startup date [Mon Jul 09 14:54:23 CST 2018]; root of context hierarchy
Windows 10系统下的列表命令为:dir
2018-07-09 14:54:23.633  INFO 14104 --- [           main] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@67a056f1: startup date [Mon Jul 09 14:54:23 CST 2018]; root of context hierarchy

猜你喜欢

转载自blog.csdn.net/jiulanhao/article/details/80966320
今日推荐