Servlet 初始化多次

问题描述

我们正在部署一个 IIS 站点,其中包括几个文件夹、几个虚拟目录和一个 Tomcat 主机。
在 Java 8 上运行 Tomcat 8 (8.0.46) 时,一切正常。 升级到JDK 9(OpenJDK 64-Bit Server VM(build 9.0.4+11,混合模式))后,我们注意到每个servlet都被初始化了几次(即init(ServletConfig)方法被执行了几次),第一次主机上下文上的时间(如预期),并为站点中的每个文件夹更改一次。
不希望有的副作用是 servlet 创建的临时文件/日志在站点的每个文件夹中重复。

Tomcat server.xml 包含主机定义:


public class PerrowAdapter extends ArrayAdapter<Perrow> {

    private Context mContext;
    private int mResource;



    public PerrowAdapter(@NonNull Context context,int resource,@NonNull ArrayList<Perrow> objects) {
        super(context,resource,objects);
        this.mContext = context;
        this.mResource = resource;

    }

    @NonNull
    @Override
    public View getView(int position,@Nullable View convertView,@NonNull ViewGroup parent) {
        LayoutInflater layoutInflater = LayoutInflater.from(mContext);
        convertView = layoutInflater.inflate(mResource,parent,false);

        TextView arabictext = convertView.findViewById(R.id.arabictext);
        TextView transliteration = convertView.findViewById(R.id.transliteration);
        TextView translation = convertView.findViewById(R.id.translation);

        arabictext.setText(getItem(position).getarabic());
        transliteration.setText(getItem(position).getTransliteration());
        translation.setText(getItem(position).getTranslation());












        return convertView;
    }
}

一个位置(C:\Program Files (x86)\b4\Controller\bin\webserver\ebsc_web)是网站的物理路径,包括文件夹,例如:applet、images等。 启动Tomcat时日志在认位置 (ebsc_web) 创建并复制到每个子文件夹中。

我们注意到,当 servlet 在正确的 servlet 上下文中初始化时,堆栈是:

      <Host name="localhost" appBase="C:/Program Files (x86)/b4/Controller/bin/webserver/ebsc_web"
            unpackWARs="true" autoDeploy="true">

        <Context path="/servlets" docBase="C:/Program Files (x86)/b4/Controller/bin/webserver\ebsc_web\"  xmlValidation="false" xmlNamespaceAware="false">
            <WatchedResource>WEB-INF/web.xml</WatchedResource>
        </Context>

        <!--
        <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
        -->

        <!-- Access log processes all example.
             Documentation at: /docs/config/valve.html
             Note: The pattern used is equivalent to using pattern="common" -->
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
      </Host>

但是当它用指向子文件夹的 servlet 上下文初始化时,堆栈是:

Daemon Thread [localhost-startStop-1] (Suspended (breakpoint at line 49 in UpdateSchedulerLoader))  
    owns: StandardWrapper  (id=63)  
    owns: StandardContext  (id=64)  
    UpdateSchedulerLoader.init(ServletConfig) line: 49  
    StandardWrapper.initServlet(Servlet) line: 1227 
    StandardWrapper.loadServlet() line: 1140    
    StandardWrapper.load() line: 1027   
    StandardContext.loadOnStartup(Container[]) line: 5038   
    StandardContext.startInternal() line: 5348  
    StandardContext(LifecycleBase).start() line: 145    
    ContainerBase$startChild.call() line: 1408  
    ContainerBase$startChild.call() line: 1398  
    FutureTask<V>.run() line: 264   
    ThreadPoolExecutor.runWorker(ThreadPoolExecutor$Worker) line: 1167  
    ThreadPoolExecutor$Worker.run() line: 641   
    Thread.run() line: 844  

所以第一次 servlet 由 Daemon Thread [localhost-startStop-1] (Suspended (breakpoint at line 42 in UpdateSchedulerLoader)) owns: StandardWrapper (id=154) owns: StandardContext (id=144) UpdateSchedulerLoader.init(ServletConfig) line: 42 StandardWrapper.initServlet(Servlet) line: 1227 StandardWrapper.loadServlet() line: 1140 StandardWrapper.load() line: 1027 StandardContext.loadOnStartup(Container[]) line: 5038 StandardContext.startInternal() line: 5348 StandardContext(LifecycleBase).start() line: 145 StandardHost(ContainerBase).addChildInternal(Container) line: 753 StandardHost(ContainerBase).addChild(Container) line: 729 StandardHost.addChild(Container) line: 717 HostConfig.deployDirectory(ContextName,File) line: 1129 HostConfig$DeployDirectory.run() line: 1871 Executors$RunnableAdapter<T>.call() line: 514 FutureTask<V>.run() line: 264 ThreadPoolExecutor.runWorker(ThreadPoolExecutor$Worker) line: 1167 ThreadPoolExecutor$Worker.run() line: 641 Thread.run() line: 844 初始化,之后由 ContainerBase$startChild.call()...

你能解释/修复这个行为吗?

解决方法

根据@PiotrP.Karwasz 的指示,通过在 server.xml 的 Host 配置中设置 autoDeploy="false" deployOnStartup="false" 解决了该问题。