zoukankan      html  css  js  c++  java
  • spring项目中的定时任务实现和问题解决

    之前我用JAVA中的Timer类实现了服务器的定时任务,具体详见之前的博文。

    后来发现了一个更简单的实现方式,利用spring中的@Scheduled注解实现觉得简单的很多。

    确实spring封装的特别好,实现起来比原来简单多了。

    下面是配置。

    在spring的xml配置中最上面加入

    xmlns:task=http://www.springframework.org/schema/task

    xsi:schemaLocation中加入

    http://www.springframework.org/schema/task 

    http://www.springframework.org/schema/task/spring-task-3.1.xsd 

    在后面加入

    <!-- 用于定时器的配置 -->

    <task:annotation-driven/>

    最后写一个定时器的类就行了,写法可以和controller类似,上面的注解不一样而已

    @Component
    public class TimeTask {
        
        @Autowired
        public IUserService userService;
        
        @Scheduled(cron="0/5 * *  * * ? ")
        public void test()
        {
            System.out.println("11111111111111111111111111111111111");
        }
    }

    然后运行项目你就能发现每5秒执行一次

    然后发现两个使用上面的问题。

    问题1:如果配置了多个定时任务,当有任务1执行时间过长的时候会阻塞任务2

    如下面所示

    @Component
    public class TimeTask {
        
        @Autowired
        public IUserService userService;
        
        @Scheduled(cron="0/5 * *  * * ? ")
        public void test()
        {
            System.out.println("11111111111111111111111111111111111");
        }
        
        @Scheduled(cron="0/1 * *  * * ? ")
        public void test2() throws InterruptedException
        {
            TimeUnit.SECONDS.sleep(10);//模拟延时10秒
            System.out.println("222222222222222222222222222222222");
        }
        
    }

    你会发现11111和22222是同时打印的,1111并不是5秒打印一次了。所以你需要配置线程池。

    把之前的spring中的配置修改为下面这样,20是线程池的大小,根据具体项目需求来设置。

    <task:annotation-driven scheduler="myScheduler"/>
        <task:scheduler id="myScheduler" pool-size="20"/>

    问题2,定时任务莫名其妙被执行两次。

    一开始就发现了这个问题,莫名其妙会输出111111和111111两次。连续两次。

    就相当任务被同时执行了两次,一开始我觉得奇怪,但是后来查询资料发现了我的一个大问题。

    在web。xml中加载了两次相同的spring配置

    就相当于spring的上下文被创建了两次,导致定时任务也就创建了两次,所以导致这个问题的发生

    一开始的配置

    <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath*:config/applicationContext.xml</param-value>
        </context-param>
        <servlet>
            <servlet-name>springMVC_dispatcher</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath*:config/applicationContext.xml</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>

    加载两个applicationContext

    后面修改成了两个配置文件

    <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath*:config/beans.xml</param-value>
        </context-param>
        <servlet>
            <servlet-name>springMVC_dispatcher</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath*:config/applicationContext.xml</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>

    一个加载定时器和controller的相关配置,一个加载数据库相关配置。

    然后就解决了。

    下面是stackoverflow中对这个问题的描述

    http://stackoverflow.com/questions/3672289/spring-3-scheduled-task-running-3-times

    深层次的原因可以看我的另一篇博文

    http://www.cnblogs.com/linkstar/p/5782027.html

    下面转载一个定时器时间上面的配置,因为定时器的时间配置不好记,所以暂时记录一下,和linux上面的定时任务很像。

    http://rainbowdesert.iteye.com/blog/2107220

    最后是spring官网的文档,我没看,英文不好

    http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html

  • 相关阅读:
    2018-10-20-WPF-通过位处理合并图片
    2019-2-11-WPF-获取应用的所有窗口
    2019-2-11-WPF-获取应用的所有窗口
    2018-8-10-WPF-如何在绑定失败异常
    2018-8-10-WPF-如何在绑定失败异常
    类和对象
    类和对象
    什么是可串行化MVCC
    LeetCode-环形链表|+环形链表||
    用js仿探探拖拽卡片的效果、飞卡片的效果,感觉挺酷,最后有美女看哦!
  • 原文地址:https://www.cnblogs.com/linkstar/p/5782117.html
Copyright © 2011-2022 走看看