我在tomcat中有30个WAR,它们之间存在依赖关系.所以我们有一个servlet来按顺序部署它们.现在我想先按顺序部署所需的应用程序,然后再并行部署它们.
我的代码如下所示.
public class MyDeployerServlet extends ManagerServlet { ... public void doGet(HttpServletRequest request,HttpServletResponse response) throws IOException,servletexception { ... if(count < serialContexts){ super.deploy(writer,context,contextName,null,false,sm); count++; } else { MyAsyncDeployer deployer = new MyAsyncDeployer(writer,sm); Thread deployerThread = new Thread(deployer); deployerThread.start(); } }
MyAsyncDeployer可运行代码是:
public class MyAsyncDeployer extends MyDeployerServlet implements Runnable{ private PrintWriter writer; private String config; private ContextName context; private String war; private boolean update; private StringManager sm; public MyAsyncDeployer(PrintWriter writer,String config,ContextName context,String war,boolean update,StringManager sm) { this.writer = writer; this.config = config; this.context = context; this.war = war; this.update = update; this.sm = sm; } public void run() { super.deploy(writer,config,sm); }
当我这样称呼时,串行部署就可以了,但是多线程部署会抛出异常.
Exception in thread "Thread-9" java.lang.NullPointerException at javax.servlet.GenericServlet.getServletContext(GenericServlet.java:123) at javax.servlet.GenericServlet.log(GenericServlet.java:188) at org.apache.catalina.manager.ManagerServlet.deploy(ManagerServlet.java:834) at com.example.servlet.MyAsyncDeployer.run(MyAsyncDeployer.java:30) at java.lang.Thread.run(Thread.java:745) Exception in thread "Thread-10" java.lang.NullPointerException at javax.servlet.GenericServlet.getServletContext(GenericServlet.java:123) at javax.servlet.GenericServlet.log(GenericServlet.java:188) at org.apache.catalina.manager.ManagerServlet.deploy(ManagerServlet.java:834) at com.example.servlet.MyAsyncDeployer.run(MyAsyncDeployer.java:30) at java.lang.Thread.run(Thread.java:745)
我无能为力,这里缺少什么,我在我的线程中使用相同的对象引用.如果有可能以多线程方式部署?
解决方法
这里的问题是你忘了初始化你的MyAsyncDeployer servlet.
您需要的是在构造之后(在启动线程之前)立即调用MyAsyncDeployer #init(ServletConfig config)方法.
对于串行情况,它可以工作,因为Tomcat在为init状态部署为javadoc之前初始化了您的servlet(MyDeployerServlet)本身:
您需要的是在构造之后(在启动线程之前)立即调用MyAsyncDeployer #init(ServletConfig config)方法.
对于串行情况,它可以工作,因为Tomcat在为init状态部署为javadoc之前初始化了您的servlet(MyDeployerServlet)本身:
Called by the servlet container to indicate to a servlet that the servlet
is being placed into service.See Servlet#init
.
This implementation stores theServletConfig
object it receives
from the servlet container for later use. When overriding this form of
the method,callsuper.init(config)
.
但只要您不需要将异步servlet部署到容器中并且只需要使用其部署能力,就没有人为您实例化它.
固定版本的代码:
if(count < serialContexts){ super.deploy(writer,sm); delpoyer.setWrapper(getWrapper()); deployer.init(getServletConfig()); Thread deployerThread = new Thread(deployer); deployerThread.start(); } }
UPD:注意,你无法避免创建servlet(也就是在Runnable#run中调用this.deploy),因为ManagerServlet#deploy方法的线程安全性是通过完全同步保证的(整个方法是同步的),所以实际上这样的方法会也是连续的.