1

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

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

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

但是,如果我将这个好的 ol' Web Application aRchive 移植到 Web Application Bundle,并且想要使用 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 中访问 Gemini Blueprint 应用程序上下文Action

日志

从日志中挑选的一些行:

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 和 processes META-INF/spring/wfadmin-context.xml,因为它被配置为执行。

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

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

<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>
4

2 回答 2

1

经过一番努力,我得到了它的工作。ContextLoaderListener仍然是要走的路,但需要进行一些调整才能使其了解 OSGi。

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

第 1 步:用 Spring OSGi 替换 Gemini Blueprint

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

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

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

由于我在<blueprint>我的一些应用程序上下文配置中使用了华丽的新根元素和命名空间,因此需要将其交换为 Spring OSGi 等价物(特别注意availability="mandatory"now 是如何变成的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中,命名空间是可互换的,但 Spring OSGi 早于 Blueprint,因此 Blueprint 命名空间等在 Spring OSGi 中不起作用。

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

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

第 3 步:让 ContextLoaderListener 感知 OSGi

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

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

经过一番搜索,我偶然发现了这篇博文并尝试了它。那里提供的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 在设置之前尝试访问它。无论哪种方式,这个答案都启发了我修改博客文章中的解决方法类以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);
    }

}

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

(好吧,我也通过使用 aBundleActivator让它工作,但这可能不是更漂亮。)

于 2013-07-04T15:50:22.113 回答
0

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

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

看看这个项目,看看实现。

于 2013-08-29T03:13:25.807 回答