java – 使用ManagerServlet进行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,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)本身:

Called by the servlet container to indicate to a servlet that the servlet
is being placed into service. See Servlet#init.
This implementation stores the ServletConfig object it receives
from the servlet container for later use. When overriding this form of
the method,call super.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方法的线程安全性是通过完全同步保证的(整个方法是同步的),所以实际上这样的方法会也是连续的.

相关文章

HashMap是Java中最常用的集合类框架,也是Java语言中非常典型...
在EffectiveJava中的第 36条中建议 用 EnumSet 替代位字段,...
介绍 注解是JDK1.5版本开始引入的一个特性,用于对代码进行说...
介绍 LinkedList同时实现了List接口和Deque接口,也就是说它...
介绍 TreeSet和TreeMap在Java里有着相同的实现,前者仅仅是对...
HashMap为什么线程不安全 put的不安全 由于多线程对HashMap进...