详解如何通过tomcat的ManagerServlet远程部署项目
介绍
之前在邮政实习时,leader让我阅读tomcat的源代码,尝试自己实现远程部署项目的功能,于是便有了这此实践。
在Tomact中有一个Manager应用程序,它是用来管理已经部署的web应用程序,在这个应用程序中,ManagerServlet是他的主servlet,通过它我们可以获取tomcat的部分指标,远程管理web应用程序,不过这个功能会受到web应用程序部署中安全约束的保护。
当你请求ManagerServlet时,它会检查getPathInfo()返回的值以及相关的查询参数,以确定被请求的操作。它支持以下操作和参数(从servlet路径开始):
请求路径
描述
/deploy?config={config-url}
根据指定的path部署并启动一个新的web应用程序(详见源码)
/deploy?config={config-url}&war={war-url}/
根据指定的pat部署并启动一个新的web应用程序(详见源码)
/deploy?path=/xxx&war={war-url}
根据指定的path部署并启动一个新的web应用程序(详见源码)
/list
列出所有web应用程序的上下文路径。格式为path:status:sessions(活动会话数)
/reload?path=/xxx
根据指定path重新加载web应用
/resources?type=xxxx
枚举可用的全局JNDI资源,可以限制指定的java类名
/serverinfo
显示系统信息和JVM信息
/sessions
此方法已过期
/expire?path=/xxx
列出path路径下的web应用的session空闲时间信息
/expire?path=/xxx&idle=mm
Expiresessionsforthecontextpath/xxxwhichwereidleforatleastmmminutes.
/sslConnectorCiphers
显示当前connector配置的SSL/TLS密码的诊断信息
/start?path=/xx
根据指定path启动web应用程序
/stop?path=/xxx
根据指定path关闭web应用程序
/threaddump
WriteaJVMthreaddump
/undeploy?path=/xxx
关闭并删除指定path的Web应用程序,然后删除底层WAR文件或文档基目录。
我们可以通过ManagerServlet中getPathInfo()提供的操作,将自己的项目远程部署到服务器上,下面将贴出我的实践代码,在实践它之前你只需要引入httpclient包和commons包。
封装统一的远程请求管理类
封装此类用于方便client请求ManagerServlet:
importjava.io.File;
importjava.net.URL;
importjava.net.URLEncoder;
importorg.apache.commons.io.IOUtils;
importorg.apache.commons.lang.StringUtils;
importorg.apache.http.Header;
importorg.apache.http.HttpHost;
importorg.apache.http.HttpResponse;
importorg.apache.http.HttpStatus;
importorg.apache.http.auth.AuthScope;
importorg.apache.http.auth.Credentials;
importorg.apache.http.auth.UsernamePasswordCredentials;
importorg.apache.http.client.AuthCache;
importorg.apache.http.client.methods.HttpGet;
importorg.apache.http.client.methods.HttpRequestBase;
importorg.apache.http.client.protocol.ClientContext;
importorg.apache.http.impl.auth.BasicScheme;
importorg.apache.http.impl.client.BasicAuthCache;
importorg.apache.http.impl.client.DefaultHttpClient;
importorg.apache.http.impl.conn.PoolingClientConnectionManager;
importorg.apache.http.protocol.BasicHttpContext;
publicclassTomcatManager{
privatestaticfinalStringMANAGER_CHARSET="UTF-8";
privateStringusername;
privateURLurl;
privateStringpassword;
privateStringcharset;
privatebooleanverbose;
privateDefaultHttpClienthttpClient;
privateBasicHttpContextlocalContext;
/**constructor*/
publicTomcatManager(URLurl,Stringusername){
this(url,username,"");
}
publicTomcatManager(URLurl,Stringusername,Stringpassword){
this(url,username,password,"ISO-8859-1");
}
publicTomcatManager(URLurl,Stringusername,Stringpassword,Stringcharset){
this(url,username,password,charset,true);
}
publicTomcatManager(URLurl,Stringusername,Stringpassword,Stringcharset,booleanverbose){
this.url=url;
this.username=username;
this.password=password;
this.charset=charset;
this.verbose=verbose;
//创建网络请求相关的配置
PoolingClientConnectionManagerpoolingClientConnectionManager=newPoolingClientConnectionManager();
poolingClientConnectionManager.setMaxTotal(5);
this.httpClient=newDefaultHttpClient(poolingClientConnectionManager);
if(StringUtils.isNotEmpty(username)){
Credentialscreds=newUsernamePasswordCredentials(username,password);
Stringhost=url.getHost();
intport=url.getPort()>-1?url.getPort():AuthScope.ANY_PORT;
httpClient.getCredentialsProvider().setCredentials(newAuthScope(host,port),creds);
AuthCacheauthCache=newBasicAuthCache();
BasicSchemebasicAuth=newBasicScheme();
HttpHosttargetHost=newHttpHost(url.getHost(),url.getPort(),url.getProtocol());
authCache.put(targetHost,basicAuth);
localContext=newBasicHttpContext();
localContext.setAttribute(ClientContext.AUTH_CACHE,authCache);
}
}
/**根据指定的path部署并启动一个新的应用程序*/
publicTomcatManagerResponsedeploy(Stringpath,Filewar,booleanupdate)throwsException{
StringBuilderbuffer=newStringBuilder("/deploy");
buffer.append("?path=").append(URLEncoder.encode(path,charset));
if(war!=null){
buffer.append("&war=").append(URLEncoder.encode(war.toString(),charset));
}
if(update){
buffer.append("&update=true");
}
returninvoke(buffer.toString());
}
/**获取所有已部署的web应用程序的上下文路径。格式为path:status:sessions(活动会话数)*/
publicTomcatManagerResponselist()throwsException{
StringBuilderbuffer=newStringBuilder("/list");
returninvoke(buffer.toString());
}
/**获取系统信息和JVM信息*/
publicTomcatManagerResponseserverinfo()throwsException{
StringBuilderbuffer=newStringBuilder("/serverinfo");
returninvoke(buffer.toString());
}
/**真正发送请求的方法*/
privateTomcatManagerResponseinvoke(Stringpath)throwsException{
HttpRequestBasehttpRequestBase=newHttpGet(url+path);
HttpResponseresponse=httpClient.execute(httpRequestBase,localContext);
intstatusCode=response.getStatusLine().getStatusCode();
switch(statusCode){
caseHttpStatus.SC_OK://200
caseHttpStatus.SC_CREATED://201
caseHttpStatus.SC_ACCEPTED://202
break;
caseHttpStatus.SC_MOVED_PERMANENTLY://301
caseHttpStatus.SC_MOVED_TEMPORARILY://302
caseHttpStatus.SC_SEE_OTHER://303
StringredirectUrl=getRedirectUrl(response);
this.url=newURL(redirectUrl);
returninvoke(path);
}
returnnewTomcatManagerResponse().setStatusCode(response.getStatusLine().getStatusCode())
.setReasonPhrase(response.getStatusLine().getReasonPhrase())
.setHttpResponseBody(IOUtils.toString(response.getEntity().getContent()));
}
/**提取重定向URL*/
protectedStringgetRedirectUrl(HttpResponseresponse){
HeaderlocationHeader=response.getFirstHeader("Location");
StringlocationField=locationHeader.getValue();
//isitarelativeLocationorafull?
returnlocationField.startsWith("http")?locationField:url.toString()+'/'+locationField;
}
}
封装响应结果集
@Data
publicclassTomcatManagerResponse{
privateintstatusCode;
privateStringreasonPhrase;
privateStringhttpResponseBody;
}
测试远程部署
在测试之前请先在配置文件放通下面用户权限:
下面是测试成功远程部署war包的代码:
importstaticorg.testng.AssertJUnit.assertEquals;
importjava.io.File;
importjava.net.URL;
importorg.testng.annotations.Test;
publicclassTestTomcatManager{
@Test
publicvoidtestDeploy()throwsException{
TomcatManagertm=newTomcatManager(newURL("http://localhost:8080/manager/text"),"sqdyy","123456");
Filewar=newFile("E:\\tomcat\\simple-war-project-1.0-SNAPSHOT.war");
TomcatManagerResponseresponse=tm.deploy("/simple-war-project-1.0-SNAPSHOT",war,true);
System.out.println(response.getHttpResponseBody());
assertEquals(200,response.getStatusCode());
//output:
//OK-Deployedapplicationatcontextpath/simple-war-project-1.0-SNAPSHOT
}
@Test
publicvoidtestList()throwsException{
TomcatManagertm=newTomcatManager(newURL("http://localhost:8080/manager/text"),"sqdyy","123456");
TomcatManagerResponseresponse=tm.list();
System.out.println(response.getHttpResponseBody());
assertEquals(200,response.getStatusCode());
//output:
//OK-Listedapplicationsforvirtualhostlocalhost
///:running:0:ROOT
///simple-war-project-1.0-SNAPSHOT:running:0:simple-war-project-1.0-SNAPSHOT
///examples:running:0:examples
///host-manager:running:0:host-manager
///manager:running:0:manager
///docs:running:0:docs
}
@Test
publicvoidtestServerinfo()throwsException{
TomcatManagertm=newTomcatManager(newURL("http://localhost:8080/manager/text"),"sqdyy","123456");
TomcatManagerResponseresponse=tm.serverinfo();
System.out.println(response.getHttpResponseBody());
assertEquals(200,response.getStatusCode());
//output:
//OK-Serverinfo
//TomcatVersion:ApacheTomcat/7.0.82
//OSName:Windows10
//OSVersion:10.0
//OSArchitecture:amd64
//JVMVersion:1.8.0_144-b01
//JVMVendor:OracleCorporation
}
}
参考资料
ManagerServlet源码地址
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。