目标:
今天在SSH项目中增添一项服务,想用来单独进行一项数据统计
方法1:
因此第一反映是写了一个线程TimingThreadListener,将监听写入到web.xml中,但是这样会有一个问题,因为在线程中我有用到了Spring中定义的service,而threadlistener的触发要比Spring容器的初始化要早,因此造成了当thread调用getBean(..)方法时,报错错误applicationContext未注入
解决办法:
既然listener的触发比注入要早,那么我就想到在listener中去手动注入,虽然问题解决了,但是总是感觉不是太合适
web.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<welcome-file-list>
<welcome-file>/login.jsp</welcome-file>
</welcome-file-list>
<!-- session有效期 -->
<session-config>
<session-timeout>100</session-timeout>
</session-config>
<!-- 统计监听 -->
<listener>
<listener-class>
com.all58.video.common.ThreadTimingListener
</listener-class>
</listener>
</web-app>
applicationContext.xml如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <context:component-scan base-package="com.all58" /> <context:annotation-config /> <!-- 初始化容器的时候自动注入 --> <bean id="appContext" class="com.all58.video.util.AppContext" /> </beans>
AppContext.java
package com.all58.video.util; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; public class AppContext implements ApplicationContextAware { private static final Log log = LogFactory.getLog(AppContext.class); private static ApplicationContext context; public void setApplicationContext(ApplicationContext context) throws BeansException { log.debug("applicationContext开始注入"); setContext(context); log.debug("applicationContext注入成功"); } public static ApplicationContext getContext() { if (context == null) throw new IllegalStateException( "applicaitonContext未注入,请在applicationContext.xml中定义AppContext"); return context; } public static void setContext(ApplicationContext context) { AppContext.context = context; } public static Object getBean(String name) throws BeansException { if (context == null) throw new IllegalStateException( "applicaitonContext未注入,请在applicationContext.xml中定义AppContext"); return context.getBean(name); } }
ThreadTimingListener.java
package com.all58.video.common; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.all58.video.util.AppContext; import com.all58.video.util.ThreadTiming; /** * @author 作者姓名 king * @version 创建时间:Apr 23, 2013 2:33:17 PM 类说明 */ public class ThreadTimingListener implements ServletContextListener { private static final Log log = LogFactory.getLog(ThreadTimingListener.class); public void contextDestroyed(ServletContextEvent arg0) { } public void contextInitialized(ServletContextEvent arg0) { log.debug("<=====手动注入applicationContext=========>"); ApplicationContext ctx = new ClassPathXmlApplicationContext( "applicationContext.xml"); AppContext.setContext(ctx); ThreadTiming thread = ThreadTiming.getThreadTiming(); log.debug("<=====监听业务开启,开始统计=====>"); try { thread.start(); } catch (Exception e) { log.error("<====监听业务开启失败=====>",e); }}}
方法2:
仍然通过thread去完成数据的统计,但是线程的触发不再通过listener去触发,而是通过写到配置文件applicationContext.xml中,当初始化程序的时候触发,但是这样会有一个问题,每当一个新的连接创建的时候,就会触发该线程的启动,虽然功能上没有问题,但是不够合理
applicaionContext.xml中加入以下信息
<bean id="hangUpThread" class="com.all58.video.util.ThreadTiming" scope="singleton" init-method="start"/>
方法3:
通过Quartz任务调度来完成