Spring定时任务Scheduled在linux tomcat服务器上总是执行两次。
在使用Spring定时任务Scheduled的时候,在本地Windows系统上,执行正常,但是在Linux生产环境上,总是启动两次,除了借助于redis以及线程安全来处理,使其只能执行一次意外,发现原因是tomcat的配置问题。
Tomcat server.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
<!-- Security listener. Documentation at /docs/config/listeners.html
<Listener className="org.apache.catalina.security.SecurityListener" />
-->
<Listener SSLEngine="on" className="org.apache.catalina.core.AprLifecycleListener"/>
<Listener className="org.apache.catalina.core.JasperListener"/>
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"/>
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/>
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener"/>
<GlobalNamingResources>
<Resource auth="Container" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase" pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase"/>
</GlobalNamingResources>
<Service name="Catalina">
<!--
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="150" minSpareThreads="4"/>
-->
<Connector connectionTimeout="20000" port="8764" protocol="HTTP/1.1" redirectPort="8443"/>
<!--
<Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
-->
<!--
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" />
-->
<!-- Define an AJP 1.3 Connector on port 8009 -->
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443"/>
<!-- You should set jvmRoute to support load-balancing via AJP ie :
<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">
-->
<Engine defaultHost="localhost" name="Catalina">
<!-- Use the LockOutRealm to prevent attempts to guess user passwords via a brute-force attack -->
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
</Realm>
<Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true">
<Context docBase="test" path="" reloadable="true"/>
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" pattern="%h %l %u %t "%r" %s %b" prefix="localhost_access_log." suffix=".txt"/>
</Host>
</Engine>
</Service>
</Server>
特别注意Host这部分配置
Host可以理解为虚拟主机,对一个Tomcat,可以配置多台虚拟主机。简单地说,就是让一台服务器可以对应多个主机名。要求每个Host的Name必须唯一。但是只建议一个Tomcat只配置一个Host。
Host的常用属性:
Name:主机名,如localhost,test.com等
appBase: 此Host的webapps目录,即存放非归档的web应用程序的目录或归档后的WAR文件的目录路径,默认是tomcat的webapps
autoDeploy:true,Tomcat处于运行状态时放置于appBase目录中的应用程序文件是否自动进行deploy;默认为true;
unpackWARs: 是否自动解压war包;默认为true;
context:类似于apache中的路径别名,一个Context定义用于标识tomcat实例中的一个Web应用程序。配置上下文,也就是对应主机下的具体子项目。
context的常用属性:
docBase: 相应的Web应用程序的存放位置;也可以使用相对路径,起始路径为此Context所属Host中appBase定义的路径;
path: 相对于Web服务器根路径而言的URI;如果为空"",则表示为此webapp的根路径;
reloadable: 是否允许重新加载此context相关的Web应用程序的类;默认为false;
特別注意这里的host和context配置,当未给Host配置Context时,Tomcat默认把ROOT项目作为Root Context,即此时访问 http://localhost:8080 就是访问ROOT项目,当给Host配置Context时,如果path="" 或 path="/",则相当于将此Context指定为Root Context,此时访问 http://localhost:8080 就是访问ROOT项目,如果在配置Context时,指定了path="" 或 path="/",同时又指定了docBase="test",则此时,在tomcat的webapps下会生成ROOT项目,并且在tomcat指定的appBase的路径下,生成一个同docBase相同名称的项目,这里就是test。此时,在tomcat里,就有了两个项目,启动tomcat,就相当于启动了两个端口相同的项目,如果使用了定时任务,则会同时执行两次。
webapps下的ROOT是tomcat的应用程序的根,如果应用程序部署在ROOT中,则可直接通过http://ip:port 访问到