本文主要介紹Tomcat啓動真正完成後(即在eclipse的控制檯上出現類似於Server started in 2300ms這樣的消息後)執行一個操作。
如下的3種方法都是在Tomcat啓動過程中執行的,這樣會影響Tomcat的啓動時間,從而造成Tomcat不能啓動成功:
1.配置一個Servlet默認自動啓動。
2.配置一個Listener來啓動
3.實現Spring的InitializingBean接口
要想不影響Tomcat的啓動,便聯想到了異步調用 。即無非就是新創建了一個線程來單獨執行,這樣Tomcat執行到相應的操作就可以直接繼續下去了,不會處於等待的狀態,避免了啓動超時。基於這樣的思想,可以有兩種方法來完成:
方法一:使用如上三種方式中的任何一種來在啓動Tomcat的過程中執行相應的方法,然後在執行的過程中使用另一個線程來執行:比如說將要執行的方法所在的類繼承HttpServlet並在web.xml中配置,然後在該Servlet的init中去調用想要執行的方法時(假設這個方法名叫start()),啓動另一個線程來執行,具體代碼如下。
- /**
- *
- */
- package com.ebay.montage.pm;
- import java.util.concurrent.Callable;
- import java.util.concurrent.FutureTask;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import org.apache.log4j.Logger;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.scheduling.annotation.Scheduled;
- import org.springframework.stereotype.Component;
- import com.ebay.montage.pm.collector.NucleonEventDataCollector;
- import com.ebay.montage.pm.constants.CMConstants;
- import com.ebay.montage.pm.utils.ConfigurationUtils;
- import com.ebay.montage.pm.utils.LoggerUtils;
- import com.ebay.system.ShutdownAwaitLatch;
- /**
- * Trigger to consume data from Nucleon Event Bus
- *
- * @author Josh Wang(Sheng)
- *
- * @email [email protected]
- */
- @Component("processor")
- public class NucleonEventProcessor extends HttpServlet {
- private static final long serialVersionUID = -9045451275234606838L;
- private static final Logger log = Logger.getLogger(NucleonEventProcessor.class);
- // Servlet的init方法會在Tomcat啓動的時候執行
- @Override
- public void init() throws ServletException {
- FutureTask<String> task = new FutureTask<String>(new Callable<String>(){
- @Override
- public String call() throws Exception {
- start(); // 使用另一個線程來執行該方法,會避免佔用Tomcat的啓動時間
- return "Collection Completed";
- }
- });
- new Thread(task).start();
- }
- // 希望Tomcat啓動結束後執行的方法
- private void start() {
- if (ConfigurationUtils.isEnableEventCollector()) {
- String topic = CMConstants.NUCLEON_EVENT_TOPIC;
- new NucleonEventDataCollector().collect(topic);
- LoggerUtils.info(log, "NuclenonEventDataCollector started to consume data from Collector Bus - NUCLEON_EVENT_TOPIC: " + topic);
- new ShutdownAwaitLatch().awaitForShutdown();
- LoggerUtils.info(log, "Complete processing and publishing Event Data");
- } else {
- log.info("There disable the collector, please enable it on dev/qa/prod property if needed");
- }
- }
- }
/**
*
*/
package com.ebay.montage.pm;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import com.ebay.montage.pm.collector.NucleonEventDataCollector;
import com.ebay.montage.pm.constants.CMConstants;
import com.ebay.montage.pm.utils.ConfigurationUtils;
import com.ebay.montage.pm.utils.LoggerUtils;
import com.ebay.system.ShutdownAwaitLatch;
/**
* Trigger to consume data from Nucleon Event Bus
*
* @author Josh Wang(Sheng)
*
* @email [email protected]
*/
@Component("processor")
public class NucleonEventProcessor extends HttpServlet {
private static final long serialVersionUID = -9045451275234606838L;
private static final Logger log = Logger.getLogger(NucleonEventProcessor.class);
// Servlet的init方法會在Tomcat啓動的時候執行
@Override
public void init() throws ServletException {
FutureTask<String> task = new FutureTask<String>(new Callable<String>(){
@Override
public String call() throws Exception {
start(); // 使用另一個線程來執行該方法,會避免佔用Tomcat的啓動時間
return "Collection Completed";
}
});
new Thread(task).start();
}
// 希望Tomcat啓動結束後執行的方法
private void start() {
if (ConfigurationUtils.isEnableEventCollector()) {
String topic = CMConstants.NUCLEON_EVENT_TOPIC;
new NucleonEventDataCollector().collect(topic);
LoggerUtils.info(log, "NuclenonEventDataCollector started to consume data from Collector Bus - NUCLEON_EVENT_TOPIC: " + topic);
new ShutdownAwaitLatch().awaitForShutdown();
LoggerUtils.info(log, "Complete processing and publishing Event Data");
} else {
log.info("There disable the collector, please enable it on dev/qa/prod property if needed");
}
}
}
web.xml中的配置
- <servlet>
- <servlet-name>event-collector</servlet-name>
- <servlet-class>com.ebay.montage.pm.NucleonEventProcessor</servlet-class>
- <load-on-startup>5</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>event-collector</servlet-name>
- <url-pattern>/event-collect</url-pattern>
- </servlet-mapping>
<servlet>
<servlet-name>event-collector</servlet-name>
<servlet-class>com.ebay.montage.pm.NucleonEventProcessor</servlet-class>
<load-on-startup>5</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>event-collector</servlet-name>
<url-pattern>/event-collect</url-pattern>
</servlet-mapping>
方法二:使用Spring的Timer或者是著名的Quartz在Tomcat啓動後再執行該方法,Spring中的Timer非常簡單,這個地方不想講解了,Quartz相對更復雜些,下面主要介紹下在Spring中怎麼樣使用Quartz來實現上面的需求:
實現Job接口的任務實現類 :
- public class InitJob implements Job {
- @Override
- public void execute(JobExecutionContext arg0) throws JobExecutionException {
- // TODO Auto-generated method stub
- }
- public void executeA() throws JobExecutionException {
- // TODO Auto-generated method stub
- .........
- }
Spring配置文件中配置的任務
- <bean id="initJob" class="com.xxx.services.InitJob" />
- <!--定時器任務配置(開始)-->
- <!--配置JOB-->
- <bean id="initJobDetail"
- class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
- <property name="targetObject" ref="initJob" />
- <property name="targetMethod" value="executeA" />
- <!-- <property name="arguments" /> -->
- </bean>
- <!--配置Trigger-->
- <bean id="initTrigger"
- class="org.springframework.scheduling.quartz.SimpleTriggerBean">
- <property name="jobDetail" ref="initJobDetail" />
- <property name="startDelay" value="1000" />
- <property name="repeatInterval" value="0" />
- <property name="repeatCount" value="0" />
- </bean>
- <!--配置Scheduler-->
- <bean id="schedulerFactory"
- class="org.springframework.scheduling.quartz.SchedulerFactoryBean" autowire="no">
- <property name="triggers">
- <list>
- <ref bean="initTrigger" />
- </list>
- </property>
- <property name="autoStartup" value="true"/>
- </bean>
- <!--定時器任務配置(結束)-->