在做WEB項目時,經常在項目第一次啟動時利用WEB容器的監聽、Servlet加載初始化等切入點為數據庫准備數據,這些初始化數據 是系統開始運行前必須的數據,例如權限組、系統選項、默認管理員等等。但是項目若不是WEB工程,或者說還沒用到WEB層(例如單元測試),這時應如何方 便地初始化數據呢?
借助Spring容器是個很好的解決方案。Spring框架提供了事件機制,而事件機制必須實現ApplicationListener監聽器,因此我們 只要編寫一個實現類實現該接口的onApplicationEvent方法,在方法體中檢測數據庫的初始化數據是否存在並選擇初始化之。
第一步:定義一個類InitData實現ApplicationListener
- import java.util.HashMap;
- import java.util.Map;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.springframework.context.ApplicationEvent;
- import org.springframework.context.ApplicationListener;
- import org.springframework.stereotype.Controller;
- import com.ebay.cloud.cms.typsafe.metadata.model.MetaClass;
- import com.ebay.tools.cms.exception.UtilityException;
- import com.ebay.tools.cms.util.CommonInterfaceUtility;
- import com.ebay.tools.cms.util.ExceptionUtils;
- import com.ebay.tools.cms.util.LoggerUtil;
- /**
- * @author Josh Wang(Sheng)
- * @email swang6@email.com
- *
- * This class used to initialize data / load data ON the application started
- */
- @Controller
- public class InitData implements ApplicationListener<ApplicationEvent> {
- private Log logger = LogFactory.getLog(InitData.class);
- private static boolean isStart = false;
- private static Map<String, MetaClass> cmsMetas = new HashMap<String, MetaClass>();
- public void onApplicationEvent(ApplicationEvent event) {
- if (!isStart) {
- isStart = true;
- LoggerUtil.info(logger, "Start to load CMS Meta data");
- try {
- cmsMetas = CommonInterfaceUtility.getMetaClass();
- } catch (UtilityException e) {
- LoggerUtil.error(logger, "Load Meta Class failed" + ExceptionUtils.getStackTraceMsg(e));
- }
- LoggerUtil.info(logger,"End to load CMS Meta data");
- LoggerUtil.info(logger,"Start to load Other data");
- LoggerUtil.info(logger,"End to load Other data");
- }
- }
第二步:解決onApplicationEvent(方法被執行兩次以上的問題:
原因:
在web 項目中(spring mvc),系統會存在兩個容器,一個是root application context ,另一個就是我們自己的 projectName-servlet context(作為root application context的子容器)。 這種情況下,就會造成onApplicationEvent方法被執行兩次。
解決方法:
如代碼所示,只需要使用一個類變量isStart即可。
需要注意的是,一定要加Annotation @Controller,這樣才表示是一個Spring的Bean(否則在相關Spring的xml中配置),才能被Spring容器處理。
第三步,寫一個Spring JunitTest,注意相關的Annotation
需要注意的就是在類上面加入如下兩個Annotation即可:
@ContextConfiguration(locations = "file:../validator-web/src/main/webapp/WEB-INF/cms-validator-servlet.xml")
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration用於加載spring的核心配置文件,因為這個操作是一個公共的操作,所以我們常常可以寫在一個BaseTest中。
- @ContextConfiguration(locations = "file:../validator-web/src/main/webapp/WEB-INF/cms-validator-servlet.xml")
- public class BaseTest {
- /**
- * Set up the environment
- * @throws Exception
- */
- @BeforeClass
- public static void setUp() throws Exception {
- }
- public static void print(String message) {
- System.out.println(message);
- }
- public static void printHighlight(String message) {
- System.err.println(message);
- }
- }
然后只需要在你的測試類上用這個Annotation:@RunWith(SpringJUnit4ClassRunner.class)
- @RunWith(SpringJUnit4ClassRunner.class)
- public class TestCacheUtil extends BaseTest {
- @Test
- public void getCMSMetaAttributeType() throws UtilityException {
- }
- }