如何在struts+spring+hibernate项目中实现对线程的监控?
在Java Web项目中,经常要在项目开始运行时启动一个线程,每隔一定的时间就运行一定的代码,比如扫描数据库的变化等等。要实现这个功能,可以现在webxml文件中定义一个Listener,然后在这个Listener中启动一个线程,在线程里面实现功能。
1 自定义Listener
在Struts+Spring+Hibernate的Web项目中,webxml里面一般都会有这样的代码:
<listener>
<listener-class>orgspringframeworkwebcontextContextLoaderListener</listener-class>
</listener>
这几句代码使得Web项目的容器(也就是Web服务器,比如Tomcat)在项目启动时实例化了一个orgspringframeworkwebcontextContextLoaderListener类。
类似的,我们也可以在webxml里面自己定义一个Listener,让Web服务器去实例化:
<xml version="10" encoding="UTF-8"><web-app xmlns:xsi="http://wwww3org/2001/XMLSchema-instance" xmlns="http://javasuncom/xml/ns/javaee" xsi:schemaLocation="http://javasuncom/xml/ns/javaee http://javasuncom/xml/ns/javaee/web-app_2_5xsd" version="25">
<filter>
<filter-name>struts2</filter-name>
<filter-class>orgapachestruts2dispatcherFilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/</url-pattern>
</filter-mapping>
<listener>
<listener-class>orgspringframeworkwebcontextContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>comXXXlistenerWSListener</listener-class>
</listener>
<welcome-file-list>
<welcome-file>indexjsp</welcome-file>
</welcome-file-list>
</web-app>
在以上的webxml文件中,我们就让Web服务器在启动时实例化我们自己定义的comXXXlistenerWSListener类(一般自己定义的Listener类要写在orgspringframeworkwebcontextContextLoaderListener的后面),然后在该类中去启动线程:
public class WSListener implements ServletContextListener{
private WSThread wsThread;
@Override public void contextDestroyed(ServletContextEvent event) { // TODO Auto-generated method stub
if (wsThread != null && wsThreadisRunning){
wsThreadstopThread();
}
}
@Override public void contextInitialized(ServletContextEvent event) { // TODO Auto-generated method stub
if (wsThread == null){
wsThread = new WSThread(event);
wsThreadstart();
}
}
}
Listener类是由Web服务器管理的,当Web服务器启动时,将Listener类实例化并调用其contextInitialized(ServletContextEvent event)方法,当Web服务器关闭时,调用其contextDestroyed(ServletContextEvent event)方法,因此我们可以分别在这两个方法里面实现线程的启动和结束。
2 在Spring容器以外获得其内部的Bean的实例的引用
被启动的线程用于间隔一定的时间扫描一次数据库,找出新增加的数据。在一般的Struts+Spring+Hibernate的Web项目中,Spring容器中的Bean是由Spring容器管理的,而我们这里启动的线程并不在Spring容器中,那么怎样获得Spring容器中Bean的实例的引用进而访问数据库呢?可以使用Spring的WebApplicationContextUtils工具类,该工具类获得Spring容器的引用,再获得其内部的Bean的实例的引用。
线程的代码:
public class WSThread extends Thread{ public volatile boolean isRunning = true; // 两次扫描之间休眠的时间
public long s_time; private WebApplicationContext context; private PropService propService; private Prop prop; private Temp2Service temp2Service; private Temp2 temp2;
private TempService tempService;
ServletContextEvent event; public WSThread(ServletContextEvent e){ thisevent = e; thiscontext = WebApplicationContextUtilsgetRequiredWebApplicationContext(eventgetServletContext()); thispropService = (PropService) contextgetBean("propService"); thistemp2Service = (Temp2Service) contextgetBean("temp2Service");
}
public void run(){ while (isRunning){ try { thisprop = propServicefindByName("scan_time"); thiss_time = IntegerparseInt(propgetValue())1000;
sleep(s_time);
Systemoutprintln("Run!!!!!!");
} catch (InterruptedException e) { // TODO Auto-generated catch block eprintStackTrace();
}
}
}
public void stopThread(){
isRunning = false;
}
public boolean isRunning(){ return isRunning;
}
}
在该线程的构造函数中,使用了从Listener传过来的ServletContextEvent变量,用该变量的getServletContext()方法,获取Web项目的servletContext,然后再以这个ServletContext作为参数,使用WebApplicationContextUtils的getRequiredWebApplicationContext()方法获取ApplicationContext对象,最后再通过ApplicationContext的getBean()方法获取到Bean的实例,实现对数据库的访问。
1连接字符串有没有写成或是连接字符串中的数据库的登陆用户名或密码有没有错误
2你的sql server2005的服务器有没有打开 可以到sql server2005目录下的外围配置看一下 服务有没有启动。
依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一个概念。具体含义是:当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在Spring里,创建被调用者的工作不再由调用者来完成,因此称为控制反转;创建被调用者实例的工作通常由Spring容器来完成,然后注入调用者,因此也称为依赖注入。
不管是依赖注入,还是控制反转,都说明Spring采用动态、灵活的方式来管理各种对象。对象与对象之间的具体实现互相透明。在理解依赖注入之前,看如下这个问题在各种社会形态里如何解决:一个人(Java实例,调用者)需要一把斧子(Java实例,被调用者)。
(1)原始社会里,几乎没有社会分工。需要斧子的人(调用者)只能自己去磨一把斧子(被调用者)。对应的情形为:Java程序里的调用者自己创建被调用者。
(2)进入工业社会,工厂出现。斧子不再由普通人完成,而在工厂里被生产出来,此时需要斧子的人(调用者)找到工厂,购买斧子,无须关心斧子的制造过程。对应Java程序的简单工厂的设计模式。
(3)进入“按需分配”社会,需要斧子的人不需要找到工厂,坐在家里发出一个简单指令:需要斧子。斧子就自然出现在他面前。对应Spring的依赖注入。
第一种情况下,Java实例的调用者创建被调用的Java实例,必然要求被调用的Java类出现在调用者的代码里。无法实现二者之间的松耦合。
第二种情况下,调用者无须关心被调用者具体实现过程,只需要找到符合某种标准(接口)的实例,即可使用。此时调用的代码面向接口编程,可以让调用者和被调用者解耦,这也是工厂模式大量使用的原因。但调用者需要自己定位工厂,调用者与特定工厂耦合在一起。
第三种情况下,调用者无须自己定位工厂,程序运行到需要被调用者时,系统自动提供被调用者实例。事实上,调用者和被调用者都处于Spring的管理下,二者之间的依赖关系由Spring提供。
所谓依赖注入,是指程序运行过程中,如果需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部的注入。Spring的依赖注入对调用者和被调用者几乎没有任何要求,完全支持对POJO之间依赖关系的管理。依赖注入通常有两种:
·设值注入。
·构造注入。
客户端
import javaioBufferedReader;
import javaioIOException;
import javaioInputStream;
import javaioInputStreamReader;
import javaioOutputStream;
import javaioPrintWriter;
import javanetSocket;
import javanetUnknownHostException;
public class EchoClient {
private String host = "localhost";
private int port = 5000;
private Socket socket = null;
public EchoClient() throws UnknownHostException, IOException {
socket = new Socket(host, port);
}
public static void main(String g[]) throws UnknownHostException,
IOException {
new EchoClient()talk();
}
private PrintWriter getWriter(Socket socket) throws IOException {
OutputStream socketOut = socketgetOutputStream(); // 首先从socket对象中获得输出的空间,即输出流,
// 再传到PrintWriter类中。
return new PrintWriter(socketOut, true); // 创建PrintWriter类,参数一:输出流,
// 参数二:为boolean值,true表示每写一行,PrintWrinter缓存就自动溢出,把数据写到目的地
}
private BufferedReader getReader(Socket socket) throws IOException {
InputStream socketIn = socketgetInputStream();// 首先从socket对象中获得输入流,再传到InputStreamReader类中。
return new BufferedReader(new InputStreamReader(socketIn));// 创建BufferedReader类,参数为InputStreamReader的对象
}
public void talk() {
BufferedReader br;
try {
br = getReader(socket);
PrintWriter pw = getWriter(socket);
BufferedReader localReader = new BufferedReader(
new InputStreamReader(Systemin));//在控制台中输入
String msg = null;
while ((msg = localReaderreadLine()) != null) {
pwprintln("Client:"+msg);
Systemoutprintln(brreadLine());
if (msgequals("bye")) {
break;
}
}
} catch (IOException e) {
eprintStackTrace();
} finally {
try {
socketclose();
} catch (IOException e) {
eprintStackTrace();
}
}
}
}
------------------------------------------------------------------
服务端
import javaioBufferedReader;
import javaioIOException;
import javaioInputStream;
import javaioInputStreamReader;
import javaioOutputStream;
import javaioPrintWriter;
import javanetServerSocket;
import javanetSocket;
public class EchoServer {
private int port = 5000; // 端口
private ServerSocket serverSoket = null; // 创建一个服务器
public EchoServer() throws IOException {
serverSoket = new ServerSocket(port); // 实例化服务器,注意:记得输入端口号
Systemoutprintln("服务器启动");
}
public String echo(String msg) {
return "echo:" + msg;
}
private PrintWriter getWriter(Socket socket) throws IOException {
OutputStream socketOut = socketgetOutputStream(); // 首先从socket对象中获得输出的空间,即输出流,
// 再传到PrintWriter类中。
return new PrintWriter(socketOut, true); // 创建PrintWriter类,参数一:输出流,
// 参数二:为boolean值,true表示每写一行,PrintWrinter缓存就自动溢出,把数据写到目的地
}
private BufferedReader getReader(Socket socket) throws IOException {
InputStream socketIn = socketgetInputStream();// 首先从socket对象中获得输入流,再传到InputStreamReader类中。
return new BufferedReader(new InputStreamReader(socketIn));// 创建BufferedReader类,参数为InputStreamReader的对象
}
public void service() {
while (true) {
Socket socket = null; // 创建一个客户端
try {
Systemoutprintln("获得连接之前");
socket = serverSoketaccept(); // 等待客户连接,accept()将返回一个socket对象,即客户连接者。
Systemoutprintln("获得连接之后");
Systemoutprintln("New connection accepted"
+ socketgetInetAddress() + ":" + socketgetPort());
BufferedReader br = getReader(socket);// 创建BufferedReader的对象并实例化
PrintWriter pw = getWriter(socket); // 创建PrintWriter的对象并实例化
String msg = null;
while ((msg = brreadLine()) != null) {//brreadLine(),本次中只能读一次。
Systemoutprintln(msg);
if (msgequals("bye")) { //如果为bye那么就退出
break;
}
BufferedReader tempbr = new BufferedReader(
new InputStreamReader(Systemin));//在控制台中输出
String tempS = tempbrreadLine();
if (tempSequals("bye")) { //如果为bye那么就退出
break;
}
pwprintln("Server:"+tempS); // 将所要回复的信息写到socket对象输出流中。
}
} catch (IOException e) {
eprintStackTrace();
} finally {
if (socket != null) {
try {
socketclose();//关闭客户端
} catch (IOException e) {
eprintStackTrace();
}
}
}
}
}
public static void main(String[] g) throws IOException {
new EchoServer()service();
}
}
一般来说HttpContext对象是Web服务器来实例化的。
因为Web服务器才知道请求、响应、Session这些是什么。你要实例化,你如何知道这些?还得借助Web服务器给你的一个HttpContext对象的信息,那么你都有现成的HttpContext了,还用自己再实例化么?
第一、前台页面表单提交方式有没有填写method="get/post",一般为post提交方式
第二、类之间需要用set/get方法的地方有没有用
第三、strust配置文件有没有配置成功,action跳转的配置
0条评论