使用ManagerServlet进行Tomcat多线程部署

时间:2016-04-29 06:04:44

标签: java multithreading tomcat

我在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, context, contextName, null, false, 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, context, null, false, 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)

我不知道这里缺少什么,我在我的线程中使用相同的对象引用。如果有可能以多线程方式部署?

1 个答案:

答案 0 :(得分:0)

这里的问题是你忘了初始化你的MyAsyncDeployer servlet。 你需要的是在构造之后(在开始一个线程之前)立即调用MyAsyncDeployer#init(ServletConfig config)方法。 对于串行情况,它可以工作,因为Tomcat在部署为MyDeployerServlet状态的javadoc之前初始化了您的servlet(init)本身:

  

由servlet容器调用,以向servlet指示servlet   正在投入使用。 See Servlet#init。   此实现存储它接收的ServletConfig对象   从servlet容器中供以后使用。当覆盖这种形式时   方法,请致电super.init(config)

但只要您不需要将异步servlet部署到容器中并且只需要使用其部署能力,就没有人为您实例化它。

修正了您的代码版本:

if(count < serialContexts){
            super.deploy(writer, context, contextName, null, false, sm);
            count++;
        } else {
            MyAsyncDeployer deployer = new MyAsyncDeployer(writer, context, contextName, null, false, sm);
            delpoyer.setWrapper(getWrapper());
            deployer.init(getServletConfig());
            Thread deployerThread = new Thread(deployer);
            deployerThread.start();
        }
}

<强> UPD: 注意,您不能避免创建servlet(在this.deploy中也称为Runnable#run),因为ManagerServlet#deploy方法的线程安全性通过完全同步得到保证(整个方法是{ {1}}),所以实际上这种方法也是连续的。