最近做了一个java的项目,部门领导给了一套代码让我尽快掌握,说心里话本人真心不喜欢java的这种项目方式,各种配置各种xml文件简直头都大了,下面就将我遇到的其中一个我认为是坑的地方整理出来,希望能帮助到后面像我一样的兄弟

功能需求说明:

使用Jsoup编写了一套爬虫程序,用来自动录入网站的数据,之前测试都是写在页面中,手动的访问页面触发爬虫(后续一些问题就是因为这样产生的),还有就是项目需要实现自动触发也就是定时器

开发过程:

既然确定是定时器,操刀子就上直接百度java定时器,发现很多quartz、spring、spring-task、Timer ,发现Timer 这东西应该是最简单粗暴的,于是在网上找到下面代码

package tasklListener;

import java.util.TimerTask;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener; import paypay.web.service.timers.ChannelDataSync; /**
* 上下文监听器,需要在web.xml中进行配置,请参见<listener></listener>结点
*
* @author Administrator
*
*/
public class MyContextListener implements ServletContextListener {
private java.util.Timer timer = null;
private ServletContext context = null; public void contextInitialized(ServletContextEvent event) {
this.context = event.getServletContext();
timer = new java.util.Timer(true);
event.getServletContext().log("定时器已启动");
// 设定MyTask中任务每5秒执行一次,0表示马上执行,可以改为2000,则表示2秒以后开始执行
// 以后都按后面指定的每5秒执行一次
timer.schedule(new MyTask(this.context), 60000, 60 * 60 * 2000);
event.getServletContext().log("已经添加任务调度表");
} public void contextDestroyed(ServletContextEvent event) {
timer.cancel();
this.context.log("定时器销毁");
this.context = null;
} private static class MyTask extends TimerTask {
private static boolean isRunning = false;
private ServletContext context = null; public MyTask(ServletContext context) {
this.context = context;
} // 下面的方法会按之前设定的每5秒执行一次,所以,此处不需要循环
public void run() {
if (!isRunning) {
isRunning = true;
context.log("开始执行指定任务"); // TODO 添加自定义的详细任务,以下只是示例
// 这里完成从数据库取数据,然后存放到MySQL数据库中
ChannelDataSync Dateuser=new ChannelDataSync();
java.text.DateFormat df = new java.text.SimpleDateFormat("yyyyMMdd") ;
java.util.Date date = new java.util.Date() ;
String datestr = df.format(new java.util.Date());
Dateuser.selectTSuserdata(datestr); isRunning = false;
context.log("指定任务执行结束");
} else {
context.log("上一次任务执行还未结束");
}
}
}
}

  

建好了类,不对啊怎么触发啊仔细看了一下注释

/**
* 上下文监听器,需要在web.xml中进行配置,请参见<listener></listener>结点
*
* @author Administrator
*
*/
于是到web.xml中找到
	<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class> </listener>

那我就直接复制listener-class节点,然后写入自己的包名+类名

<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
<listener-class>
com.shopping.zy.MyContextListener
</listener-class>
</listener>

编译后报错(大神别鄙视我,我是真的java新手,对于配置什么xm文件完全不会啊 )

看了一下报错信息:cvc-complex-type.2.4.d: Invalid content was found starting with element 'listener-class'. No child element is expected at this point.

本人的英文很烂,但也大概看出来说是子元素有问题,既然是子元素不对,那就重新写一个对象不就行了 ,于是配置文件改成:

	<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class> </listener>
<listener>
<listener-class>
com.shopping.zy.MyContextListener
</listener-class> </listener>

测试通过!

再接下来就是在MyContextListener类中做操作了 首先是在定时器的初始化方法contextInitialized中:

         timer = new java.util.Timer(true);
event.getServletContext().log("定时器已启动");
//1000*60*60 1秒 *60=1分钟 *2 等于开启后60分钟执行采集任务
//(1000*60*60)*12 (1000*60*60)=1个小时 *12表示没12小时执行一次
int tempint=(1000*60*60)*(Integer.parseInt(sysconfig.getAotoupdate_step()));
timer.schedule(new MyTask(this.context), 1000*60*60,(1000*60*60)*(Integer.parseInt(sysconfig.getAotoupdate_step())));

具体的可以参看代码,schedule函数的参数是分别是,要调用的函数,延迟执行时间,执行间隔时间 我提供的代码中最后的的执行间隔时间是动态在数据库中取出的所以是动态的,你也可以直接写成固定的

到这了你们肯定觉得没什么坑啊,那么我就先来介绍一下第一个坑:

首先在MyContextListener是不可以直接使用srping的对象的,即使你声明了对应的对象,但由于MyContextListener的启动线程和spring不一致(我自己理解的,如果谁知道可以给我解释一下),在MyContextListener类中使用spring对象是不会有实例化相关的注入对象的,这就坑爹了,总不能自己把所有的数据库操作类重新做一遍吧,于是乎又是神器出山,继续百度,找了半天发现一个帖子中的解决办法:

		 ISysConfigService sysConfigService;
WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(event.getServletContext());
sysConfigService = (ISysConfigService) context.getBean("sysConfigService");
SysConfig sysconfig= sysConfigService.getSysConfig();

这里里面有一点是需要注意的:context.getBean("sysConfigService")中的sysConfigService为实体类是我项目中的操作类,但是通过context.getBean()方法返回的对象类型必须是其对应的ISysConfigService接口,而不是其对象类型,

虽然不知道是为什么但我觉得这肯定跟spring的设计模式有关系,这是不是就是工厂类的设计模式啊,在此处坑了我很久也是今天我想写这篇博文的一个诱因吧。这样得到的对象是包括其本身的注入对象的。

接下来就是要实现调用我写好的爬虫函数了 ,这简单啊 ,直接实例化类对象 然后调用方法就行了 ,由于类对象中没有注入对象不需要使用上面的方法,说干就干

ManageHT mht=new ManageHT();

mht.zy_sr_cj(context);
mht.cj_start(context);
mht.zy_collect_news();

 三个方法分别是我对应的三个采集的函数,之前接收的是HttpServletRequest ,但是在MyContextListener中我不知道如何获取,于是我就讲context传入了,如果你知道怎么获取可以给我留言,这不是重点因为后续我使用了其他的办法,

使用上面的方式访问对应的函数会遇到和之前一样的问题,对应的注入对象无法加载,弄了半天最后决定坚持我的简单粗暴的原则,既然直接网页访问可以, MyContextListener不可以,那我就模拟一个网页请求不就行了 还研究什么注入不注入对象的

说干就干:

	   public static String doGet(String url, String queryString, String charset, boolean pretty) {
StringBuffer response = new StringBuffer();
HttpClient client = new HttpClient();
HttpMethod method = new GetMethod(url);
try {
if (StringUtils.isNotBlank(queryString))
//对get请求参数做了http请求默认编码,好像没有任何问题,汉字编码后,就成为%式样的字符串
method.setQueryString(URIUtil.encodeQuery(queryString));
client.executeMethod(method);
if (method.getStatusCode() == HttpStatus.SC_OK) {
BufferedReader reader = new BufferedReader(new InputStreamReader(method.getResponseBodyAsStream(), charset));
String line;
while ((line = reader.readLine()) != null) {
if (pretty)
response.append(line).append(System.getProperty("line.separator"));
else
response.append(line);
}
reader.close();
}
} catch (URIException e) { } catch (IOException e) { } finally {
method.releaseConnection();
}
return response.toString();
}

模拟get请求的操作,对于我的需求来说get/post没什么区别,直接百度一段代码,

最后的调用部分代码变成:

					 String sr = doGet("http://localhost:8080/shopping/admin/testsr.htm", null, "UTF-8", true);
Thread thread = Thread.currentThread();
thread.sleep(1000*60*10);//暂停10分钟后程序继续执行
String mr = doGet("http://localhost:8080/shopping/admin/zy_collect_mr.htm", null, "UTF-8", true);
Thread threadsecond = Thread.currentThread();
threadsecond.sleep(1000*60*10);//暂停10分钟后程序继续执行
String news = doGet("http://localhost:8080/shopping/admin/zy_collect_news.htm", null, "UTF-8", true);

运行项目:执行定时器-执行任务-调用我的爬虫页面,看着数据一条一条进入到数据库中,今天的努力没白费,作为一个新手java程序员我想两说,虽然我对java了解不深,但是java的一些机制确实导致了项目开发进度的缓慢(就是大牛你也得承认,java开发效率就是比.net、python、php)等慢多了 ,这只是我接触java项目以后遇到的比较简单的,之前焦头烂额的也没记录下来,希望以后能把我遇到的问题总结出来,如果再有.net转java的兄弟,希望能让你少走一些弯路。

spring项目中如何添加定时器以及在定时器中自动生成sprng注入对象的更多相关文章

  1. .net core 中简单封装Dapper.Extensions 并使用sqlsuger自动生成实体类

    引言 由公司需要使用dapper  同时支持多数据库 又需要支持实体类 又需要支持sql 还需要支持事务 所以采用了 dapper + dapperExtensions  并配套 生成实体类小工具的方 ...

  2. Spring进阶之路(10)-Advice简单介绍以及通过cglib生成AOP代理对象

    Advice简单介绍 1. Before:在目标方法运行之前运行织入.假设Before的处理中没有进行特殊的处理.那么目标方法终于会运行,可是假设想要阻止目标方法运行时.能够通过抛出一个异常来实现.B ...

  3. Mybatis自动生成的BO对象继承公共父类(BO中过滤掉公共属性)

    使用mybatis的代码生成工具:mybatis-generator,如果自动生成的BO都有公共的属性,则可以指定这些BO继承父类(父类中定义公共属性) 1.定义父类 注意:属性public,不要使用 ...

  4. 利用Django中的url方法实现地址动态拼接自动生成超链接地址

    目标 建立一个图书列表页面,显示图书名列表,并实现点击书名跳转到图书详细页面,显示图书详细信息. URL方法简介 功能:返回一个绝对路径的引用(不包含域名的URL):该引用匹配一个给定的视图函数和 一 ...

  5. Spring JPA 使用@CreatedDate、@CreatedBy、@LastModifiedDate、@LastModifiedBy 自动生成时间和修改者

    JPA Audit 在spring jpa中,支持在字段或者方法上进行注解@CreatedDate.@CreatedBy.@LastModifiedDate.@LastModifiedBy,从字面意思 ...

  6. pycharm中使用配置好的virtualenv环境,自动生成和安装requirements.txt依赖

    1.手动建立: 第一步 建立虚拟环境 Windows cmd: pip install virtualenv 创建虚拟环境目录 env 激活虚拟环境 C:\Python27\Scripts\env\S ...

  7. 给.Net Core添加Swagger实现接口文档自动生成

    1.添加Nuget相关引用 Swashbuckle.AspNetCore

  8. mybatis 添加后获得该新增数据自动生成的 id

    // useGeneratedKeys默认值为false,keyProperty的值对应的是User类中的主键字段名 // mybatis 写法如下 <insert id="inser ...

  9. 淘淘商城项目_同步索引库问题分析 + ActiveMQ介绍/安装/使用 + ActiveMQ整合spring + 使用ActiveMQ实现添加商品后同步索引库_匠心笔记

    文章目录 1.同步索引库问题分析 2.ActiveM的介绍 2.1.什么是ActiveMQ 2.2.ActiveMQ的消息形式 3.ActiveMQ的安装 3.1.安装环境 3.2.安装步骤 4.Ac ...

随机推荐

  1. Oracle数据库定时任务配置和日志执行情况查询

    基础配置: /***************************************************************** * * 移动抵扣券快到期推送提醒 * 首次执行 : 2 ...

  2. 关于div的居中的问题

    (从已经死了一次又一次终于挂掉的百度空间人工抢救出来的,发表日期2014-01-11) div水平和垂直居中,text-align和vertical-align不起作用,因为标签div没有这两个属性, ...

  3. 神秘常量复出!用0x077CB531计算末尾0的个数 -- De Bruijn 序列

    http://www.matrix67.com/blog/archives/3985 神秘常量复出!用0x077CB531计算末尾0的个数 大家或许还记得 Quake III 里面的一段有如天书般的代 ...

  4. CSS实现标题右侧“更多”

    HTML < h2>< a h ref="#" >标题< /a> < span>更多…< /span> < /h2 ...

  5. SCCM2007

    Active Directory系统组发现:此方法按照上次运行发现方法时 Active Directory 中的响应返回对象,可发现活动目录OU.全局组.通用组.嵌套组.非安全组. Active Di ...

  6. Sql中的union和union all的讲解

    SQL UNION 和 UNION ALL操作符 UNION 操作符用于合并两个或多个 SELECT 语句的结果集. 请注意,UNION 内部的 SELECT 语句必须拥有相同数量的列.列也必须拥有相 ...

  7. C++ map注意事项

    1.在map中,由key查找value时,首先要判断map中是否包含key. 2.如果不检查,直接返回map[key],可能会出现意想不到的行为.如果map包含key,没有问题,如果map不包含key ...

  8. Python之美[从菜鸟到高手]--深刻理解原类(metaclass)

    本来想自己写这篇文章的,可当我读了这篇文章http://blog.jobbole.com/21351/,我打消了这个念头,因为肯定写的没有人家的好,说的通俗易懂,面面俱到.就厚着面皮修改下格式,测试下 ...

  9. MySql 日期格式化函数date_format()

    mysql> select date_format(now(),'%Y'); +-------------------------+ | date_format(now(),'%Y') | +- ...

  10. Cocos2d-x 3.1 内存管理机制

    Cocos2d-x使用的内存管理方式是引用计数.引用计数是一种非常有效的机制.通过给每个对象维护一个引用计数器,记录该对象当前被引用的次数.当对象添加一次引用时,计数器加1:而对象失去一次引用时.计数 ...