2011-09-16 53 views
2

我有一個Spring應用程序,該應用程序在Jetty的嵌入式實例中啓動REST服務,該實例本身是從Spring啓動的。是否可以從Web上下文中找到Spring非Web上下文?

最初的Spring上下文有一個集成和數據庫層,並啓動Jetty實例。 Jetty然後調用它自己的公開REST服務的應用程序上下文文件。

我想知道是否有某種方法將初始Spring上下文暴露給Jetty內運行的Web上下文。不幸的是我不能部署一個完整的J2EE服務器,並且我很猶豫從Web上下文中運行所有的東西,依靠Jetty來管理線程等等。

回答

1

所以我還沒有發現過基於從上面ericacm一個更好的答案。更好的唯一原因是您仍然可以使用<load-on-startup>作爲web.xml文件中的servlet。

嵌入Jetty服務器時,需要創建WebAppContext。超類ContextHandler可讓您設置EventListener的數組,其中包括ServletContextListener

所以解決方案擴展爲ContextLoader並實現了Spring的ApplicationContextAwareServletContextListener接口。加載器可讓您返回由contextaware界面設置的父上下文,並且偵聽器通過contextInitialized()爲您提供ServletContext

然後,您可以在任何Jetty組件之前對其進行初始化,並在Jetty服務器加載時訪問完全填充的ServletContext,在初始化任何Web應用程序之前調用該服務器。

監聽器實現:

import javax.servlet.ServletContext; 
import javax.servlet.ServletContextEvent; 
import javax.servlet.ServletContextListener; 

import org.springframework.beans.BeansException; 
import org.springframework.context.ApplicationContext; 
import org.springframework.context.ApplicationContextAware; 
import org.springframework.web.context.ContextLoader; 

public final class EmbeddedJettySpringContextLoaderListener extends ContextLoader implements ApplicationContextAware, ServletContextListener 
{ 
    private ApplicationContext applicationContext; 

    @Override 
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 
     this.applicationContext = applicationContext; 
    } 

    /** 
    * Returns the parent application context as set by the 
    * {@link ApplicationContextAware} interface. 
    * 
    * @return The initial ApplicationContext that loads the Jetty server. 
    */ 
    @Override 
    protected ApplicationContext loadParentContext(ServletContext servletContext) { 
     return this.applicationContext; 
    } 

    @Override 
    public void contextInitialized(ServletContextEvent sce) { 
     super.initWebApplicationContext(sce.getServletContext()); 
    } 

    @Override 
    public void contextDestroyed(ServletContextEvent sce) { 
     //not needed 
    } 
} 

碼頭配置爲WebAppContext(最終由服務器所引用):

<!-- Loads this application context as the parent of the web application context. --> 
<bean id="parentContextLoaderListener" class="com.citi.matrix.server.restapi.EmbeddedJettySpringContextLoaderListener" /> 

<bean id="restApiWebAppContext" class="org.mortbay.jetty.webapp.WebAppContext"> 
    <property name="displayName" value="RestApi" /> 
    <property name="contextPath" value="/" /> 
    <!-- the value for war, must be a relative path to the root of the application, and does not use the classpath. --> 
    <property name="war" value="${WEBAPPS_HOME}/rest-api" /> 
    <property name="eventListeners"> 
    <ref local="parentContextLoaderListener" /> 
    </property> 
    <property name="configurationClasses"> 
    <list> 
     <value>org.mortbay.jetty.webapp.WebInfConfiguration</value> 
     <value>org.mortbay.jetty.webapp.WebXmlConfiguration</value> 
     <value>org.mortbay.jetty.webapp.JettyWebXmlConfiguration</value> 
    </list> 
    </property> 
    <property name="logUrlOnStart" value="true" /> 
</bean> 
+0

您仍然需要不在web.xml中聲明ContextLoaderListener,因爲嵌入式實現需要在父上下文中聲明。由於您沒有調用ContextLoaderListener,因此您仍然需要在web.xml中設置contextConfigLocation context-param。 –

3

我假設你在碼頭的web.xml有ContextLoaderListener,那就是得到的是如何創建Spring的web內容。

  1. 取出ContextLoaderListener 從碼頭的web.xml(但保持context-paramcontextConfigLocation

  2. 子類ContextLoader,覆蓋loadParentContext() 返回您最初的Spring上下文。

  3. 啓動後碼頭創建ContextLoader 子類的實例。

  4. 呼叫initWebApplicationContext(context.getServletContext().getContext()) 在這種情況下,在「背景」是org.mortbay.jetty.servlet.Context

+0

完全錯過了這一點。我現在沒有時間去嘗試,但我真的很高興能這樣做,因爲這意味着一次減少依賴。將盡快更新。謝謝。 –

+0

這工作,雖然有幾個警告。首先,您需要將contextPath提供給.getContext()方法。第二個是你無法在啓動時加載任何servlet,因爲查找默認的servlet上下文將失敗。 對我而言,這並不是什麼大不了的事情,而且這種工作完美無瑕。如果可以的話,我會再次投票。 –

相關問題