Spring-Boot中如何使用多线程处理任务方法

看到这个标题,相信不少人会感到疑惑,回忆你们自己的场景会发现,在Spring的项目中很少有使用多线程处理任务的,没错,大多数时候我们都是使用Spring MVC开发的web项目,默认的Controller,Service,Dao组件的作用域都是单实例,无状态,然后被并发多线程调用,那么如果我想使用多线程处理任务,该如何做呢?

比如如下场景:

使用spring-boot开发一个监控的项目,每个被监控的业务(可能是一个数据库表或者是一个pid进程)都会单独运行在一个线程中,有自己配置的参数,总结起来就是:

(1)多实例(多个业务,每个业务相互隔离互不影响)

(2)有状态(每个业务,都有自己的配置参数)

如果是非spring-boot项目,实现起来可能会相对简单点,直接new多线程启动,然后传入不同的参数类即可,在spring的项目中,由于Bean对象是spring容器管理的,你直接new出来的对象是没法使用的,就算你能new成功,但是bean里面依赖的其他组件比如Dao,是没法初始化的,因为你饶过了spring,默认的spring初始化一个类时,其相关依赖的组件都会被初始化,但是自己new出来的类,是不具备这种功能的,所以我们需要通过spring来获取我们自己的线程类,那么如何通过spring获取类实例呢,需要定义如下的一个类来获取SpringContext上下文:

/**
 * Created by Administrator on 2016/8/18.
 * 设置Sping的上下文
 */
@Component
public class ApplicationContextProvider implements ApplicationContextAware {

 private static ApplicationContext context;

 private ApplicationContextProvider(){}

 @Override
 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  context = applicationContext;
 }

 public static <T> T getBean(String name,Class<T> aClass){
  return context.getBean(name,aClass);
 }
}

然后定义我们的自己的线程类,注意此类是原型作用域,不能是默认的单例:

@Component("mTask")
@Scope("prototype")
public class MoniotrTask extends Thread {

 final static Logger logger= LoggerFactory.getLogger(MoniotrTask.class);
 //参数封装
 private Monitor monitor;

 public void setMonitor(Monitor monitor) {
  this.monitor = monitor;
 }

 @Resource(name = "greaterDaoImpl")
 private RuleDao greaterDaoImpl;

 @Override
 public void run() {
  logger.info("线程:"+Thread.currentThread().getName()+"运行中.....");
 }

}

写个测试例子,测试下使用SpringContext获取Bean,查看是否是多实例:

/**
 * Created by Administrator on 2016/8/18.
 */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes =ApplicationMain.class)
public class SpingContextTest {

 @Test
 public void show()throws Exception{
  MoniotrTask m1= ApplicationContextProvider.getBean("mTask", MoniotrTask.class);
  MoniotrTask m2=ApplicationContextProvider.getBean("mTask", MoniotrTask.class);
  MoniotrTask m3=ApplicationContextProvider.getBean("mTask", MoniotrTask.class);
  System.out.println(m1+" => "+m1.greaterDaoImpl);
  System.out.println(m2+" => "+m2.greaterDaoImpl);
  System.out.println(m3+" => "+m3.greaterDaoImpl);

 }

}

运行结果如下:

[ INFO ] [2016-08-25 17:36:34] com.test.tools.SpingContextTest [57] - Started SpingContextTest in 2.902 seconds (JVM running for 4.196)
2016-08-25 17:36:34.842  INFO 8312 --- [           main] com.test.tools.SpingContextTest          : Started SpingContextTest in 2.902 seconds (JVM running for 4.196)
Thread[Thread-2,5,main] => com.xuele.bigdata.xalert.dao.rule.impl.GreaterDaoImpl@285f38f6
Thread[Thread-3,5,main] => com.xuele.bigdata.xalert.dao.rule.impl.GreaterDaoImpl@285f38f6
Thread[Thread-4,5,main] => com.xuele.bigdata.xalert.dao.rule.impl.GreaterDaoImpl@285f38f6

可以看到我们的监控类是多实例的,它里面的Dao是单实例的,这样以来我们就可以在spring中使用多线程处理我们的任务了。

如何启动我们的多线程任务类,可以专门定义一个组件类启动也可以在启动Spring的main方法中启动,下面看下,如何定义组件启动:

@Component
public class StartTask {

 final static Logger logger= LoggerFactory.getLogger(StartTask.class);

 //定义在构造方法完毕后,执行这个初始化方法
 @PostConstruct
 public void init(){

  final List<Monitor> list = ParseRuleUtils.parseRules();
  logger.info("监控任务的总Task数:{}",list.size());
  for(int i=0;i<list.size();i++) {
   MoniotrTask moniotrTask= ApplicationContextProvider.getBean("mTask", MoniotrTask.class);
   moniotrTask.setMonitor(list.get(i));
   moniotrTask.start();
   logger.info("第{}个监控task: {}启动 !",(i+1),list.get(i).getName());
  }
 }
}

最后备忘下logback.xml,里面可以配置相对和绝对的日志文件路径:

<!-- Logback configuration. See http://logback.qos.ch/manual/index.html -->
<configuration scan="true" scanPeriod="10 seconds">
 <!-- Simple file output -->
 <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
 <!--<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">-->
 <!-- encoder defaults to ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
 <encoder>
  <pattern>
   [ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n
  </pattern>
  <charset>UTF-8</charset> <!-- 此处设置字符集 -->
 </encoder>

 <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  <!-- rollover daily 配置日志所生成的目录以及生成文件名的规则,默认是相对路径 -->
  <fileNamePattern>logs/xalert-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
  <!--<property name="logDir" value="E:/testlog" />-->
  <!--绝对路径定义-->
  <!--<fileNamePattern>${logDir}/logs/xalert-%d{yyyy-MM-dd}.%i.log</fileNamePattern>-->
  <timeBasedFileNamingAndTriggeringPolicy
   class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
  <!-- or whenever the file size reaches 64 MB -->
  <maxFileSize>64 MB</maxFileSize>
  </timeBasedFileNamingAndTriggeringPolicy>
 </rollingPolicy>

 <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
  <level>DEBUG</level>
 </filter>
 <!-- Safely log to the same file from multiple JVMs. Degrades performance! -->
 <prudent>true</prudent>
 </appender>

 <!-- Console output -->
 <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
 <!-- encoder defaults to ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
  <encoder>
   <pattern>
    [ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n
   </pattern>
   <charset>UTF-8</charset> <!-- 此处设置字符集 -->
  </encoder>
 <!-- Only log level WARN and above -->
 <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
  <level>INFO</level>
 </filter>
 </appender>

 <!-- Enable FILE and STDOUT appenders for all log messages.
  By default, only log at level INFO and above. -->
 <root level="INFO">
  <appender-ref ref="STDOUT" />
  <appender-ref ref="FILE" />

 </root>

 <!-- For loggers in the these namespaces, log at all levels. -->
 <logger name="pedestal" level="ALL" />
 <logger name="hammock-cafe" level="ALL" />
 <logger name="user" level="ALL" />
 <include resource="org/springframework/boot/logging/logback/base.xml"/>
 <jmxConfigurator/>
</configuration>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Spring Boot 配置和使用多线程池的实现

    某些情况下,我们需要在项目中对多种任务分配不同的线程池进行执行.从而通过监控不同的线程池来控制不同的任务.为了达到这个目的,需要在项目中配置多线程池. spring boot 提供了简单高效的线程池配置和使用方案. 配置 首先是配置线程池的bean交给spring 管理: @Configuration public class TaskExecutePool { @Bean(name ="threadPoolA") public ThreadPoolTaskExecutormyTask

  • Spring boot多线程配置方法

    本文实例为大家分享了Spring boot多线程配置的具体代码,供大家参考,具体内容如下 1.配置线程配置类 package test; import java.util.concurrent.Executor; import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; import org.springframework.context.annotation.ComponentScan; import o

  • 解决SpringBoot项目使用多线程处理任务时无法通过@Autowired注入bean问题

    最近在做一个"温湿度控制"的项目,项目要求通过用户设定的温湿度数值和实时采集到的数值进行比对分析,因为数据的对比与分析是一个通过前端页面控制的定时任务,经理要求在用户开启定时任务时,单独开启一个线程进行数据的对比分析,并将采集到的温湿度数值存入数据库中的历史数据表,按照我们正常的逻辑应该是用户在请求开启定时任务时,前端页面通过调用后端接口,创建一个新的线程来执行定时任务,然后在线程类中使用 @Autowired 注解注入保存历史数据的service层,在线程类中调用service层保存

  • spring boot中多线程开发的注意事项总结

    前言 Springt通过任务执行器(TaskExecutor)来实现多线程和并发编程.使用ThreadPoolTaskExecutor可实现一个基于线程池的TaskExecutor.而实际开发中任务一般是非阻碍的,即异步的,所以我们要在配置类中通过@EnableAsync 开启对异步任务的支持,并通过实际执行Bean的方法中使用@Async注解来声明其是一个异步任务. 基于springboot的多线程程序开发过程中,由于本身也需要注入spring容器进行管理,才能发挥springboot的优势.

  • 详解Springboot对多线程的支持

    这两天看阿里的JAVA开发手册,到多线程的时候说永远不要用 new Thread()这种方式来使用多线程.确实是这样的,我一直在用线程池,到了springboot才发现他已经给我们提供了很方便的线程池机制. 本博客代码托管在github上https://github.com/gxz0422042... 一.介绍 Spring是通过任务执行器(TaskExecutor)来实现多线程和并发编程,使用ThreadPoolTaskExecutor来创建一个基于线城池的TaskExecutor.在使用线程

  • 详解Spring-Boot中如何使用多线程处理任务

    看到这个标题,相信不少人会感到疑惑,回忆你们自己的场景会发现,在Spring的项目中很少有使用多线程处理任务的,没错,大多数时候我们都是使用Spring MVC开发的web项目,默认的Controller,Service,Dao组件的作用域都是单实例,无状态,然后被并发多线程调用,那么如果我想使用多线程处理任务,该如何做呢? 比如如下场景: 使用spring-boot开发一个监控的项目,每个被监控的业务(可能是一个数据库表或者是一个pid进程)都会单独运行在一个线程中,有自己配置的参数,总结起来

  • Spring Boot中使用MongoDB数据库的方法

    MongoDB数据库简介 简介 MongoDB是一个高性能,开源,无模式的,基于分布式文件存储的文档型数据库,由C++语言编写,其名称来源取自"humongous",是一种开源的文档数据库──NoSql数据库的一种.NoSql,全称是 Not Only Sql,指的是非关系型的数据库. 特点 MongoDB数据库的特点是高性能.易部署.易使用,存储数据非常方便.主要功能特性有: * 面向集合存储,易存储对象类型的数据. * 模式自由. * 支持动态查询. * 支持完全索引,包含内部对象

  • Spring Boot 中使用cache缓存的方法

    一.什么是缓存 Cache Cache 一词最早来自于CPU设计 当CPU要读取一个数据时,首先从CPU缓存中查找,找到就立即读取并送给CPU处理:没有找到,就从速率相对较慢的内存中读取并送给CPU处理,同时把这个数据所在的数据块调入缓存中,可以使得以后对整块数据的读取都从缓存中进行,不必再调用内存.正是这样的读取机制使CPU读取缓存的命中率非常高(大多数CPU可达90%左右),也就是说CPU下一次要读取的数据90%都在CPU缓存中,只有大约10%需要从内存读取.这大大节省了CPU直接读取内存的

  • 在Spring Boot中实现HTTP缓存的方法

    缓存是HTTP协议的一个强大功能,但由于某些原因,它主要用于静态资源,如图像,CSS样式表或JavaScript文件,但是,HTTP缓存不仅限于这些,还可以将其用于动态计算的资源. 通过少量工作,您可以加快应用程序并改善整体用户体验.在本文中,您将学习 如何使用内置的HTTP响应缓存机制来实现缓存SpringBoot控制器的结果 . 1.如何以及何时使用HTTP响应缓存? 您可以在应用程序的多个层上进行缓存.数据库具有其缓存存储,Web客户端也在其需要重用的信息.HTTP协议负责网络通信.缓存机

  • Spring Boot中使用JDBC Templet的方法教程

    前言 Spring 的 JDBC Templet 是 Spring 对 JDBC 使用的一个基本的封装.他主要是帮助程序员实现了数据库连接的管理,其余的使用方式和直接使用 JDBC 没有什么大的区别. 业务需求 JDBC 的使用大家都比较熟悉了.这里主要为了演示在 SpringBoot 中使用 Spring JDBC Templet 的步骤,所以我们就设计一个简单的需求.一个用户对象的 CURD 的操作.对象有两个属性,一个属性是id,一个属性是名称.存储在 MySQL 的 auth_user

  • Spring Boot中使用Spring-data-jpa的配置方法详解

    为了解决这些大量枯燥的数据操作语句,我们第一个想到的是使用ORM框架,比如:hibernate.通过整合Hibernate之后,我们以操作Java实体的方式最终将数据改变映射到数据库表中. 为了解决抽象各个Java实体基本的"增删改查"操作,我们通常会以泛型的方式封装一个模板Dao来进行抽象简化,但是这样依然不是很方便,我们需要针对每个实体编写一个继承自泛型模板Dao的接口,再编写该接口的实现.虽然一些基础的数据访问已经可以得到很好的复用,但是在代码结构上针对每个实体都会有一堆Dao的

  • Spring Boot中利用JavaMailSender发送邮件的方法示例(附源码)

    快速入门 在Spring Boot的工程中的pom.xml中引入spring-boot-starter-mail依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency> 如其他自动化配置模块一样,在完成了依赖引入之后,只需要在applicatio

  • Spring boot中PropertySource注解的使用方法详解

    前言 本文将重点讲解一下Spring中@PropertySource注解的使用,如何通过PropertySource注解加载指定的配置文件.以及PropertySource注解与@ConfigurationProperties两个注解的配合使用.下面话不多说了,来随着小编来一起学习学习吧. 1.1. PropertySource注解加载指定的属性文件 Spring框架提供了PropertySource注解,目的是加载指定的属性文件,接下来我们看一下如何使用该注解.首先我们定义一个配置类,并在类中

  • spring boot 中设置默认网页的方法

    废话不多说,直接上代码,相信都能看的懂 一共两布,第一步,创建Interceptor拦截 package com.cy.example.config; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.slf4j.Logger; import org.slf4j.

  • Spring Boot中自动化配置的利弊以及解决方法

    本文主要给大家介绍了关于Spring Boot自动化配置的利弊及解决方法的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍: Spring Boot中的双刃剑:自动化配置 在之前的文章中,我们通过各种功能性示例体验了Spring Boot的自动化配置给我们所带来的超便利的新开发方式.但是,在一些情况下Spring Boot的自动化配置也会给我们惹来不少的麻烦,比如这些场景: 项目依赖复杂的情况下,由于依赖方的依赖组织不够严格,可能引入了一些实际我们不需要的依赖,从而导致我们

  • 详解Spring Boot中MyBatis的使用方法

    orm框架的本质是简化编程中操作数据库的编码,发展到现在基本上就剩两家了,一个是宣称可以不用写一句SQL的hibernate,一个是可以灵活调试动态sql的mybatis,两者各有特点,在企业级系统开发中可以根据需求灵活使用.发现一个有趣的现象:传统企业大都喜欢使用hibernate,互联网行业通常使用mybatis. hibernate特点就是所有的sql都用Java代码来生成,不用跳出程序去写(看)sql,有着编程的完整性,发展到最顶端就是spring data jpa这种模式了,基本上根据

随机推荐