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

时间:2013-07-04 08:34:01

标签: spring struts osgi blueprint-osgi struts-1

在一个好的战争项目中,你只需在你的ContextLoaderListener中添加一个web.xml即可,而且你可以使用

WebApplicationContextUtils.getWebApplicationContext(getServlet().getServletContext())
例如,

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

但是,如果我将这个优秀的'Web应用程序aRchive移植到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"/>
<{1>}中的

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

xmlns:osgi

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

为了完整起见,Spring-Blueprint配置看起来像这样:

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] (由两者加载):

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

2 个答案:

答案 0 :(得分:1)

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

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

步骤1:用Spring OSGi替换Gemini Blueprint

我们需要ContextLoaderListener创建OsgiBundleXmlWebApplicationContext而不是普通XmlWebApplicationContext。据我所知,还没有任何Gemini Blueprint提供这个类的分布,所以我们需要使用Spring OSGi而不是分发 spring-osgi-web 包。

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

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

由于我在一些应用程序上下文配置中使用了华而不实的新<blueprint>根元素和命名空间,因此需要将其交换为Spring OSGi等价物(特别注意availability="mandatory"现在如何成为{ {1}}):

cardinality="1..1"

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

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

这是通过简单地将我的应用程序上下文移出<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> 而将它们放在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对我不起作用,我仍然遇到同样的错误。通过在这个新的上下文类型中添加一些跟踪输出,我可以确认实际上bundle上下文不存在:

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

似乎从未在ServletContext上设置BundleContext,或者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工作了,但这可能不是更漂亮。)

答案 1 :(得分:0)

spring-dm-web的替代品是 Gemini Web ,它有一个Web扩展程序组件。它适用于我,但我需要使用JavaConfig风格的appContext。不知何故,当我使用XML进行配置时,它不会检测蓝图命名空间。我没有尝试过Struts,但尝试过Spring-MVC,这很好。

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

查看this项目以查看实施情况。