上一篇,寫了struts2中的關鍵問題,至於詳細的集成過程,我就不細表了,除了我描述的關鍵問題之外,其餘的都雷同。下面說說Spring的集成,網上搜的文章中大多介紹spring和struts2的集成,都是同一套路,將spring的配置往src根目錄一扔,而後在web.xml中配個監聽器,而後在struts2的配置中增長struts.objectFactory的描述。就完了,雖然好用,可是都是照葫蘆畫瓢,不知因此然。其實struts既然有這個個描述,那就意味着,struts2中全部實例的獲取,都要經過這個定義的ObjectFactory來獲取,工廠裏用什麼方式獲取對象就和什麼集成,因此,和spring的集成關鍵不在web.xml的配置上,甚至web.xml上的監聽能夠徹底不要。下面咱們就來實際的作一下:編寫XKStrutsSpringObjectFactory繼承SpringObjectFactory, 代碼以下:html
- public class XKStrutsSpringObjectFactory extends SpringObjectFactory
- {
- /**
- *
- */
- private static final long serialVersionUID = 1L;
- private static final Logger LOG = LoggerFactory.getLogger(XKStrutsSpringObjectFactory.class);
- @SuppressWarnings("deprecation")
- @Inject
- public XKStrutsSpringObjectFactory(@Inject(value = StrutsConstants.STRUTS_OBJECTFACTORY_SPRING_AUTOWIRE, required = false) String autoWire,
- @Inject(value = StrutsConstants.STRUTS_OBJECTFACTORY_SPRING_AUTOWIRE_ALWAYS_RESPECT, required = false) String alwaysAutoWire,
- @Inject(value = StrutsConstants.STRUTS_OBJECTFACTORY_SPRING_USE_CLASS_CACHE, required = false) String useClassCacheStr, @Inject ServletContext servletContext,
- @Inject(StrutsConstants.STRUTS_DEVMODE) String devMode, @Inject Container container)
- {
- super();
- boolean useClassCache = "true".equals(useClassCacheStr);
- if (LOG.isInfoEnabled())
- {
- LOG.info("Initializing Struts-Spring integration...");
- }
- // 關鍵代碼
- Object rootWebApplicationContext = Initialization.getInstance().getApplicationContext();
- if (rootWebApplicationContext instanceof RuntimeException)
- {
- RuntimeException runtimeException = (RuntimeException) rootWebApplicationContext;
- LOG.fatal(runtimeException.getMessage());
- return;
- }
- ApplicationContext appContext = (ApplicationContext) rootWebApplicationContext;
- if (appContext == null)
- {
- // uh oh! looks like the lifecycle listener wasn't installed. Let's
- // inform the user
- String message = "********** FATAL ERROR STARTING UP STRUTS-SPRING INTEGRATION **********\n" + "Looks like the Spring listener was not configured for your web app! \n"
- + "Nothing will work until WebApplicationContextUtils returns a valid ApplicationContext.\n" + "You might need to add the following to web.xml: \n" + " <listener>\n"
- + " <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>\n" + " </listener>";
- LOG.fatal(message);
- return;
- }
- String watchList = container.getInstance(String.class, "struts.class.reloading.watchList");
- String acceptClasses = container.getInstance(String.class, "struts.class.reloading.acceptClasses");
- String reloadConfig = container.getInstance(String.class, "struts.class.reloading.reloadConfig");
- if ("true".equals(devMode) && StringUtils.isNotBlank(watchList) && appContext instanceof Cla***eloadingXMLWebApplicationContext)
- {
- // prevent class caching
- useClassCache = false;
- Cla***eloadingXMLWebApplicationContext reloadingContext = (Cla***eloadingXMLWebApplicationContext) appContext;
- reloadingContext.setupReloading(watchList.split(","), acceptClasses, servletContext, "true".equals(reloadConfig));
- if (LOG.isInfoEnabled())
- {
- LOG.info("Class reloading is enabled. Make sure this is not used on a production environment!", watchList);
- }
- setClassLoader(reloadingContext.getReloadingClassLoader());
- // we need to reload the context, so our isntance of the factory is
- // picked up
- reloadingContext.refresh();
- }
- this.setApplicationContext(appContext);
- int type = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME; // default
- if ("name".equals(autoWire))
- {
- type = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
- }
- else if ("type".equals(autoWire))
- {
- type = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;
- }
- else if ("auto".equals(autoWire))
- {
- type = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;
- }
- else if ("constructor".equals(autoWire))
- {
- type = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;
- }
- else if ("no".equals(autoWire))
- {
- type = AutowireCapableBeanFactory.AUTOWIRE_NO;
- }
- this.setAutowireStrategy(type);
- this.setUseClassCache(useClassCache);
- this.setAlwaysRespectAutowireStrategy("true".equalsIgnoreCase(alwaysAutoWire));
- if (LOG.isInfoEnabled())
- {
- LOG.info("... initialized Struts-Spring integration successfully");
- }
- }
- }
關鍵一步就在於第26行,那句代碼,只要使用本身的方法得到applicationContext對象就好了。而Spring對於ApplicationContext對象也提供了多種實現,既然我們想本身定義配置的名稱和位置,那麼我們就使用FileSystemXmlApplicationContext,嗯,這個類的使用就不用我贅述了。很簡單,實例化的時候將配置的路徑傳入就ok了。最後在struts的配置中,將咱們本身實現的工廠類應用上去,如:web
- <constant name="struts.objectFactory" value="com.xk.commons.config.XKStrutsSpringObjectFactory" />
要注意一點:代碼71行中使用到了Cla***eloadingXMLWebApplicationContext這個類,這個類的父類中會實現FilesystemAlterationListener接口,這個接口在struts和spring提供的jar包中是找不到的,其包含在apache的commons的jci庫中,具體到jar包爲commons-jci-fam-1.0.jar 下載地址:http://commons.apache.org/jci/downloads.html。spring