如何从 Struts1 Action 访问 Gemini Blueprint 应用程序上下文?

Posted

技术标签:

【中文标题】如何从 Struts1 Action 访问 Gemini Blueprint 应用程序上下文?【英文标题】:How to access a Gemini Blueprint application context from a Struts1 Action? 【发布时间】:2013-07-02 04:19:24 【问题描述】:

在一个好的 ol'war 项目中,您只需将 ContextLoaderListener 添加到您的 web.xml 就可以了 - 您可以使用

WebApplicationContextUtils.getWebApplicationContext(getServlet().getServletContext())

例如,从 Struts 1 Action 类访问应用程序上下文,整个配置过程是 well documented。如果它们是由其他应用程序创建的,您可以从 JNDI 中查找 bean。

但是,如果我将这个优秀的 Web 应用程序存档移植到 Web 应用程序包,并且想要使用 OSGi 服务引用而不是 JNDI,该怎么办?如果我想要 Spring 做的只是在我的 Web 应用程序中管理 bean,那么上述方法仍然有效。我可以通过上述实用方法实例化 bean 并获取它们,并且我已经成功设置 Gemini Blueprint(以前称为 Spring DM)来解析我的 OSGi 服务引用。

问题在于 Gemini Blueprint 和 Spring Struts 并行运行并且似乎彼此不了解。上述实用程序方法返回的上下文不包含由 Gemini Blueprint 创建的 bean,例如从 OSGi 服务导入的 bean,如果我将 Blueprint 样式的 OSGi 服务引用添加到 Spring Struts 解析的 XML 配置,则会可怕地死掉。

我需要做什么才能从 Struts 1 Action 中访问 Gemini Blueprint 应用程序上下文?

日志

从日志中挑选的一些行:

17:12:32,206 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-1) JBAS015876: Starting deployment of "wfadmin-1.0-SNAPSHOT-82a5028.war" (runtime-name: "wfadmin-1.0-SNAPSHOT-82a5028.war")

17:12:36,744 INFO  [io.undertow.servlet] (MSC service thread 1-7) Initializing Spring root WebApplicationContext
17:12:36,745 INFO  [org.springframework.web.context.ContextLoader] (MSC service thread 1-7) Root WebApplicationContext: initialization started
17:12:36,751 INFO  [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] (MSC service thread 1-7) Loading XML bean definitions from ServletContext resource [/META-INF/spring/wfadmin-context.xml]
17:12:38,026 FINE  [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] (MSC service thread 1-7) Loaded 1 bean definitions from location pattern [/META-INF/spring/wfadmin-context.xml]
17:12:38,026 FINE  [org.springframework.web.context.support.XmlWebApplicationContext] (MSC service thread 1-7) Bean factory for Root WebApplicationContext: org.springframework.beans.factory.support.DefaultListableBeanFactory@440f89d6: defining beans [testBeanInMetaInfSpringWfadmiContextXml]; root of factory hierarchy
17:12:38,027 INFO  [org.springframework.beans.factory.support.DefaultListableBeanFactory] (MSC service thread 1-7) Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@440f89d6: defining beans [testBeanInMetaInfSpringWfadmiContextXml]; root of factory hierarchy
17:12:38,030 FINE  [org.springframework.beans.factory.support.DefaultListableBeanFactory] (MSC service thread 1-7) Finished creating instance of bean 'testBeanInMetaInfSpringWfadmiContextXml'
17:12:38,034 INFO  [org.springframework.web.context.ContextLoader] (MSC service thread 1-7) Root WebApplicationContext: initialization completed in 1289 ms

17:12:38,140 INFO  [org.eclipse.gemini.blueprint.extender.support.DefaultOsgiApplicationContextCreator] (MSC service thread 1-7) Discovered configurations osgibundle:/META-INF/spring/*.xml in bundle [Sunstone Workflow Admin (se.sunstone.workflow.web)]
17:12:38,208 FINEST [org.eclipse.gemini.blueprint.io.OsgiBundleResourcePatternResolver] (EclipseGeminiBlueprintExtenderThread-15) Resolved location pattern [osgibundle:/META-INF/spring/*.xml] to resources [URL [bundle://se.sunstone.workflow.web-87-1-0/META-INF/spring/wfadmin-context.xml], URL [bundle://se.sunstone.workflow.web-87-1-0/META-INF/spring/wfadmin-osgi-context.xml]]
17:12:38,258 FINE  [org.eclipse.gemini.blueprint.context.support.OsgiBundleXmlApplicationContext] (EclipseGeminiBlueprintExtenderThread-15) Bean factory for OsgiBundleXmlApplicationContext(bundle=se.sunstone.workflow.web, config=osgibundle:/META-INF/spring/*.xml): org.springframework.beans.factory.support.DefaultListableBeanFactory@22eccb06: defining beans [testBeanInMetaInfSpringWfadmiContextXml,testBeanInMetaInfSpringWfadminOsgiContextXml,wfEngine]; root of factory hierarchy
17:12:38,260 FINEST [org.eclipse.gemini.blueprint.extender.internal.dependencies.startup.MandatoryImporterDependencyFactory] (EclipseGeminiBlueprintExtenderThread-15) Discovered single proxy importers [&wfEngine]
17:12:38,266 FINE  [org.springframework.beans.factory.support.DefaultListableBeanFactory] (EclipseGeminiBlueprintExtenderThread-15) Finished creating instance of bean 'wfEngine'
17:12:38,266 FINEST [org.eclipse.gemini.blueprint.extender.internal.dependencies.startup.MandatoryImporterDependencyFactory] (EclipseGeminiBlueprintExtenderThread-15) Eager importer &wfEngine implies dependecy DependencyService[Name=&wfEngine][Filter=(objectClass=se.sunstone.workflow.WorkflowEngine)][Mandatory=true]
17:12:38,266 FINE  [org.eclipse.gemini.blueprint.extender.internal.dependencies.startup.DependencyServiceManager] (EclipseGeminiBlueprintExtenderThread-15) OSGi service dependency for importer [&wfEngine] is already satisfied
17:12:38,266 FINEST [org.eclipse.gemini.blueprint.extender.internal.dependencies.startup.DependencyServiceManager] (EclipseGeminiBlueprintExtenderThread-15) Total OSGi service dependencies beans [&wfEngine]
17:12:38,292 FINE  [org.springframework.beans.factory.support.DefaultListableBeanFactory] (EclipseGeminiBlueprintExtenderThread-16) Finished creating instance of bean 'testBeanInMetaInfSpringWfadmiContextXml'
17:12:38,293 FINE  [org.springframework.beans.factory.support.DefaultListableBeanFactory] (EclipseGeminiBlueprintExtenderThread-16) Finished creating instance of bean 'testBeanInMetaInfSpringWfadminOsgiContextXml'

17:12:46,978 FINEST [se.sunstone.util.web.AbstractAction] (default task-1) Beans defined in application context Root WebApplicationContext : 
17:12:46,978 FINEST [se.sunstone.util.web.AbstractAction] (default task-1) testBeanInMetaInfSpringWfadmiContextXml
17:12:46,978 FINEST [se.sunstone.util.web.AbstractAction] (default task-1) End of beans defined in application context Root WebApplicationContext
17:12:46,979 FINEST [org.springframework.beans.factory.support.DefaultListableBeanFactory] (default task-1) No bean named 'wfEngine' found in org.springframework.beans.factory.support.DefaultListableBeanFactory@440f89d6: defining beans [testBeanInMetaInfSpringWfadmiContextXml]; root of factory hierarchy
17:12:46,979 SEVERE [se.sunstone.util.web.AbstractAction] (default task-1) A requested bean does not exist.: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'wfEngine' is defined
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:568)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1108)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:278)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1117)
    at se.sunstone.util.web.AbstractAction.getService(AbstractAction.java:53) [AbstractAction.class:]
    ...

第一部分(不包括顶部的唯一行)告诉ContextLoaderListener 启动 Spring ContextLoader 并处理 META-INF/spring/wfadmin-context.xml,就像它配置的那样。

第二部分告诉 Gemini Blueprint 检测到这是一个 Blueprint 包并从配置 META-INF/spring/wfadmin-,osgi-context.xml 启动它自己的上下文。我们还看到 bean wfEngine 已成功从 OSGi 服务导入。

第三部分显示了我的se.sunstone.util.web.AbstractAction 在尝试访问 Spring Struts 应用程序上下文中的 bean wfEngine 时是如何死掉的。这是意料之中的,因为workflow-context.xml 只包含testBeanInMetaInfSpringWorkflowContextXml bean,但如果我包含

<osgi:reference id="wfEngineInMetaInfSpringWfAdminContextXml" interface="se.sunstone.workflow.WorkflowEngine"/>

workflow-context.xml(具有合适的xmlns:osgi 定义)中,Web 应用程序甚至无法启动:

09:43:30,026 SEVERE [org.springframework.web.context.ContextLoader] (MSC service thread 1-4) Context initialization failed: org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace [http://www.springframework.org/schema/osgi]
Offending resource: ServletContext resource [/META-INF/spring/wfadmin-context.xml]

我希望有一种方法可以告诉 Spring Strugs 插件与 Gemini Blueprint 共享其应用程序上下文。这可能吗?

为了完整起见,Spring-Blueprint 配置如下所示:

META-INF/spring/wfadmin-context.xml(两者都加载):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:osgi="http://www.springframework.org/schema/osgi"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
           http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd">

  <bean id="testBeanInMetaInfSpringWfadmiContextXml" class="java.lang.Object"/>
  <!--<osgi:reference id="wfEngineInMetaInfSpringWfAdminContextXml" interface="se.sunstone.workflow.WorkflowEngine"/>-->

</beans>

META-INF/spring/wfadmin-osgi-context.xml(由 Gemini 蓝图加载):

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">

  <bean id="testBeanInMetaInfSpringWfadminOsgiContextXml" class="java.lang.Object"/>
  <reference id="wfEngine" interface="se.sunstone.workflow.WorkflowEngine" availability="mandatory"/>

</blueprint>

【问题讨论】:

我发现了这个:static.springsource.org/osgi/docs/current/reference/html/…,它看起来很有希望,除了它是关于 Spring DM 而不是它的继任者 Gemini Blueprint。有谁知道是否有与spring-osgi-web.jar 等对应的类似文档和/或 Gemini Blueprint jars? 我想我正在做一些事情:我找到了this,现在正试图让它与 Spring DM(双子座前)扩展罐一起工作。 【参考方案1】:

经过一番努力,我得到了它的工作。 ContextLoaderListener 仍然是可行的方法,但需要进行一些调整才能使其能够识别 OSGi。

我的解决方案包括几个步骤:

第 1 步:用 Spring OSGi 替换 Gemini 蓝图

我们需要让ContextLoaderListener 创建一个OsgiBundleXmlWebApplicationContext 而不是普通的XmlWebApplicationContext。据我所知,目前还没有任何提供此类的 Gemini Blueprint 发行版,因此我们需要使用 Spring OSGi 来代替,它已经分发了 spring-osgi-web 包。

我没有使用 Gemini Blueprint 扩展 jar,而是使用了以下 Spring OSGi jar:

spring-osgi-core-1.2.1.jar spring-osgi-extender-1.2.1.jar spring-osgi-io-1.2.1.jar spring-osgi-web-1.2.1.jar

(当然还有它们的依赖关系,为简洁起见省略)

由于我在一些应用程序上下文配置中使用了华丽的新 &lt;blueprint&gt; 根元素和命名空间,因此需要将其替换为 Spring OSGi 等效项(特别注意 availability="mandatory" 现在如何变为 cardinality="1..1"):

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:osgi="http://www.springframework.org/schema/osgi"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
           http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd">
    <reference id="wfEngine" interface="se.sunstone.workflow.WorkflowEngine" cardinality="1..1"/>
</beans>

在 Gemini Blueprint the namespaces are interchangeable 中,但 Spring OSGi 早于 Blueprint,因此 Blueprint 命名空间等在 Spring OSGi 中不起作用。

第 2 步:防止 Spring OSGi 将战争识别为 Spring 捆绑包

这是通过简单地将我的应用程序上下文移出META-INF/spring 并将它们放置在WEB-INF/applicationContext.xml 中来实现的,这是 ContextLoaderListener 查找应用程序上下文配置的默认位置。

第 3 步:让 ContextLoaderListener 感知 OSGi

接下来,我按照these instructions 配置 ContextLoaderListener 以使用org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicationContext 作为应用程序上下文的类型。然后这给我带来了一个新错误:

java.lang.IllegalArgumentException: bundle context should be set before refreshing the application context

经过一番搜索,我偶然发现了this blog post 并尝试了它。那里提供的OsgiWebBundleContext 对我不起作用,我仍然遇到同样的错误。通过在这个新的上下文类型中添加一些跟踪输出,我可以确认捆绑上下文实际上并不存在:

17:15:20,233 FINEST [se.sunstone.workflow.web.osgi.workaround.OsgiBundleXmlWebApplicationContextWithCorrectBundleContextLookupName] (MSC service thread 1-5) Attributes in servletContext:
17:15:20,233 FINEST [se.sunstone.workflow.web.osgi.workaround.OsgiBundleXmlWebApplicationContextWithCorrectBundleContextLookupName] (MSC service thread 1-5) org.apache.jasper.JSP_PROPERTY_GROUPS
17:15:20,233 FINEST [se.sunstone.workflow.web.osgi.workaround.OsgiBundleXmlWebApplicationContextWithCorrectBundleContextLookupName] (MSC service thread 1-5) javax.servlet.context.tempdir
17:15:20,233 FINEST [se.sunstone.workflow.web.osgi.workaround.OsgiBundleXmlWebApplicationContextWithCorrectBundleContextLookupName] (MSC service thread 1-5) org.apache.jasper.JSP_TAG_LIBRARIES
17:15:20,233 FINEST [se.sunstone.workflow.web.osgi.workaround.OsgiBundleXmlWebApplicationContextWithCorrectBundleContextLookupName] (MSC service thread 1-5) javax.websocket.server.ServerContainer
17:15:20,234 FINEST [se.sunstone.workflow.web.osgi.workaround.OsgiBundleXmlWebApplicationContextWithCorrectBundleContextLookupName] (MSC service thread 1-5) org.apache.jasper.SERVLET_VERSION
17:15:20,234 FINEST [se.sunstone.workflow.web.osgi.workaround.OsgiBundleXmlWebApplicationContextWithCorrectBundleContextLookupName] (MSC service thread 1-5) org.jboss.as.jsf.FACES_ANNOTATIONS
17:15:20,234 FINEST [se.sunstone.workflow.web.osgi.workaround.OsgiBundleXmlWebApplicationContextWithCorrectBundleContextLookupName] (MSC service thread 1-5) org.apache.tomcat.InstanceManager
17:15:20,234 FINEST [se.sunstone.workflow.web.osgi.workaround.OsgiBundleXmlWebApplicationContextWithCorrectBundleContextLookupName] (MSC service thread 1-5) End of attributes in servletContext

但至少 Spring 现在已经支持 OSGi,这是一个开始。

第 4 步:解决缺少的 BundleContext

似乎 BundleContext 从未在 ServletContext 上设置,或者 Spring 在设置之前尝试访问它。无论哪种方式,this answer 启发我修改博客文章中的解决方法类,以使用FrameworkUtil.getBundle(ClassFromBundle).getBundleContext() 来查找 BundleContext:

public class OsgiBundleXmlWebApplicationContextSettingBundleContextFromFrameworkUtil
        extends OsgiBundleXmlWebApplicationContext 
    @Override
    public void setServletContext(ServletContext servletContext) 
        if(getBundleContext() == null) 
            BundleContext context = FrameworkUtil.getBundle(getClass()).getBundleContext();
            if(context != null) 
                setBundleContext(context);
            
        

        // to call "this.servletContext = servletContext;" in super
        super.setServletContext(servletContext);
    


这对我有用!这可能不是最漂亮的解决方案,但它是迄今为止我开始工作的唯一解决方案。*

(好吧,我也通过using a BundleActivator 让它工作了,但这可能不是更漂亮。)

【讨论】:

【参考方案2】:

spring-dm-web 的替代品是 Gemini Web,它有一个网络扩展器组件。它对我有用,但我需要使用 JavaConfig 样式的 appContext。不知何故,当我使用 XML 进行配置时,它没有检测到蓝图命名空间。我没有尝试 Struts,但尝试了 Spring-MVC,效果很好。

问题是从服务注册表中查找 OSGi 服务。我必须创建一个激活器,然后从那里获取服务,使用 @Bean 创建一个 bean 并使用 @Autowired 将该服务注入到所需的类中。

查看this 项目以查看实现。

【讨论】:

以上是关于如何从 Struts1 Action 访问 Gemini Blueprint 应用程序上下文?的主要内容,如果未能解决你的问题,请参考以下文章

Struts1和Struts2的区别

JAVA,Struts1里,怎么从一个Action方法里跳到另一个Action方法里

struts1和struts2的区别

SSH学习笔记—从配置Struts1环境到简单实例

struts1 & jquery form 文件异步上传

struts1 & jquery form 文件异步上传