在一个好的战争项目中,你只需在你的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
答案 0 :(得分:1)
经过一番努力,我得到了它的工作。 ContextLoaderListener
仍然是要走的路,但需要进行一些调整才能让OSGi知道。
我的案例中的解决方案包括几个步骤:
我们需要ContextLoaderListener
创建OsgiBundleXmlWebApplicationContext
而不是普通XmlWebApplicationContext
。据我所知,还没有任何Gemini Blueprint提供这个类的分布,所以我们需要使用Spring OSGi而不是分发 spring-osgi-web 包。
我没有使用Gemini Blueprint扩展器罐,而是使用了以下Spring OSGi罐子:
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
(当然还有它们的依赖关系,为简洁而省略)
由于我在一些应用程序上下文配置中使用了华而不实的新<blueprint>
根元素和命名空间,因此需要将其交换为Spring OSGi等价物(特别注意availability="mandatory"
现在如何成为{ {1}}):
cardinality="1..1"
在Gemini Blueprint the namespaces are interchangeable中,但是Spring OSGi早于Blueprint,因此Blueprint名称空间等在Spring OSGi中不起作用。
这是通过简单地将我的应用程序上下文移出<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查找应用程序上下文配置的默认位置。
接下来,我按照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意识到了,这是一个开始。
似乎从未在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项目以查看实施情况。