1、引言
由于web应用的特殊性,使得网页只能被用户访问后才能被动执行,然后处理相应的业务,但是有时候我们也需要某些组件去保持在后台运行,即使用户不访问也能在后台不断处理数据,而不是又去写一个普通的java程序来执行这项业务,这里我就使用servlet组件来实现这个功能。
2、实现原理
前面我已经说了,web应用只能被用户访问后才能执行,这一点是无法改变的。因此,如果要让servlet程序在后台自己循环运行,那就只能直接访问自己,而且为了不导致栈溢出,我们不能使用递归实现,这里选择使用分线程完成这个功能。
3、实现步骤
3.1、导入依赖
这里我是在maven项目中实现的,首先需要导入httpclient框架的依赖,后面要用到,如果不是maven项目中请导入对应的jar包,依赖版本如下:
<!--httpclient爬虫框架引入-->
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.0.1</version>
</dependency>
3.2、创建启动和停止的标志
在一个独立的servlet程序在定义如下两个静态变量用于开启后台运行服务和测试:
private static int id=0;//执行次数
private static String isEnd="end";//长度等于3时停止,1时开始
3.3、创建线程池
由于要频繁使用分线程,所以最好使用线程池,代码如下:
private static ExecutorService service = Executors.newFixedThreadPool(2);
static {
ThreadPoolExecutor service1 = (ThreadPoolExecutor) service;
}
3.4、控制启动和关闭
下面是控制启动和关闭的核心代码,保证该服务只能启动一次,这里需要将该代码放在get请求中,主要是为了便于演示和启动程序:
String end = request.getParameter("end");
if (end.equals("n") && isEnd.equals("e")){//自身调用
backThread();
}
if (end.equals("e") && !isEnd.equals("e")){//外部启动循环调用
isEnd=end;
id=0;
backThread();
}
if (end.equals("end")){//外部停止循环调用
isEnd=end;
}
3.5、后台处理的逻辑代码
后台处理逻辑放在这里,里面的延时操作根据需要修改
/**
* 执行后台逻辑处理功能
*/
private static void backThread(){
service.execute(() -> {
try {
Thread.sleep(3000);//延时5秒
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet("http://192.168.0.106:8080/payBack?end=n");
CloseableHttpResponse response = httpClient.execute(httpGet);
if (response.getStatusLine().getStatusCode()==200){
System.out.println("我第" + id + "次执行");
id++;
httpClient.close();
response.close();
}
} catch (Exception e) {
e.printStackTrace();
}
});
}
3.6、完整代码
package com.pay.maven.sevlet.pay;
import org.apache.commons.httpclient.HttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 支付端后台线程,后面需要改变睡眠时间
*/
@WebServlet("/payBack")
public class BackThreadServlet extends HttpServlet {
private static int id=0;//执行次数
private static String isEnd="end";//长度等于3时停止,1时开始
private static ExecutorService service = Executors.newFixedThreadPool(2);
static {
ThreadPoolExecutor service1 = (ThreadPoolExecutor) service;
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
String end = request.getParameter("end");
if (end.equals("n") && isEnd.equals("e")){//自身调用
backThread();
}
if (end.equals("e") && !isEnd.equals("e")){//外部启动循环调用
isEnd=end;
id=0;
backThread();
}
if (end.equals("end")){//外部启动循环调用
isEnd=end;
}
response.setContentType("text/plain; charset=utf-8");//文本类型数据
response.getWriter().write(""+id);
}
/**
* 执行后台功能
*/
private static void backThread(){
service.execute(() -> {
try {
Thread.sleep(3000);//延时5秒
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet("http://192.168.0.106:8080/payBack?end=n");
CloseableHttpResponse response = httpClient.execute(httpGet);
if (response.getStatusLine().getStatusCode()==200){
System.out.println("我第" + id + "次执行");
id++;
httpClient.close();
response.close();
}
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
4、效果演示
4.1、启动方法
在浏览器访问下方地址,IP换成自己的真实地址:
http://192.168.0.106:8080/payBack?end=e
4.2、停止方法
在浏览器访问下方地址,IP换成自己的真实地址:
http://192.168.0.106:8080/payBack?end=end