在OSGi容器中加载spring dm

时间:2015-09-01 07:44:53

标签: spring-mvc osgi spring-annotations sling spring-dm

我正在尝试在我的OSGi包中加载spring dm。我跟着tutorial。我的目标是,对于特定的URL,URL应该由spring而不是默认的sling servlet处理。我在实现同样的目标方面取得了部分成功。

有时,它不起作用。我的globaldispatcher servlet没有被初始化。 问题是间歇性的 。有时我的spring servlet初始化很好。但有时我会收到这个错误:

[SpringOsgiExtenderThread-2] net.jasonday.examples.sling.spring.mvc.sling.SlingDispatcherServlet FrameworkServlet 'globaldispatcher': initialization started
[SpringOsgiExtenderThread-2] net.jasonday.examples.sling.spring.mvc.sling.SlingDispatcherServlet Context initialization failed
java.lang.IllegalArgumentException: bundle context should be set before refreshing the application context
at org.springframework.util.Assert.notNull(Assert.java:112)
at org.springframework.osgi.context.support.AbstractDelegatedExecutionApplicationContext.normalRefresh(AbstractDelegatedExecutionApplicationContext.java:179)
at org.springframework.osgi.context.support.AbstractDelegatedExecutionApplicationContext$NoDependenciesWaitRefreshExecutor.refresh(AbstractDelegatedExecutionApplicationContext.java:89)
at org.springframework.osgi.context.support.AbstractDelegatedExecutionApplicationContext.refresh(AbstractDelegatedExecutionApplicationContext.java:175)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:467)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:483)
at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:358)
at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:325)
at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:127)
at javax.servlet.GenericServlet.init(GenericServlet.java:158)
at org.apache.sling.servlets.resolver.internal.SlingServletResolver.createServlet(SlingServletResolver.java:988)
at org.apache.sling.servlets.resolver.internal.SlingServletResolver.bindServlet(SlingServletResolver.java:936)
at sun.reflect.GeneratedMethodAccessor36.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)

Java版本:1.7.0_45

我正在使用tutorial中提到的以下依赖项:(所有都是OSGi包)

Spring AOP v3.0.6.RELEASE 
Spring ASM v3.0.6.RELEASE 
Spring Aspects v3.0.6.RELEASE 
Spring Beans v3.0.6.RELEASE 
Spring Context v3.0.6.RELEASE 
Spring Context Support v3.0.6.RELEASE 
Spring Core v3.0.6.RELEASE 
Spring Expression v3.0.6.RELEASE
Spring Web v3.0.6.RELEASE 
Spring Web Servlet v3.0.6.RELEASE 
Spring OSGi IO v1.2.1 
Spring OSGi Core v1.2.1 
Spring OSGi Extender v1.2.1 
Spring OSGi Annotation v1.2.1 
Spring OSGi Web v1.2.1 
AOP Alliance v1.0.0
CGLib 2.2.0
Commons Lang v2.6 
Commons Codec v1.5 
Commons Logging v1.1.1 
ASM v3.2.0 
JSR 330 (javax.inject) v1.0.0 
JSR 250 (javax.annotation) v1.0.0

以下是我的spring-osgi.xml中的代码,该代码存在于META-INF / spring /文件夹中

 <osgi:service ref="globalSlingDispatcherServlet">
<osgi:interfaces>
  <value>javax.servlet.Servlet</value>
</osgi:interfaces>

<osgi:service-properties>
  <entry key="sling.servlet.resourceTypes" value="examples/sling/spring/mvc/dispatcher/global" />
  <entry key="sling.servlet.extensions">
    <array>
      <value>json</value>
      <value>html</value>
    </array>
  </entry>
  <entry key="sling.servlet.methods">
    <array>
      <value>GET</value>
      <value>POST</value>
    </array>
  </entry>
  <entry key="contextClass" value="org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicationContext"/>
  <entry key="sling.core.servletName" value="globaldispatcher" />
</osgi:service-properties>

以下是META-INF \ spring \ spring.xml

的代码
<context:annotation-config />
<context:component-scan base-package="net.jasonday.examples.sling.spring.mvc.sling" />
<aop:aspectj-autoproxy />
<bean class="org.springframework.osgi.extensions.annotation.ServiceReferenceInjectionBeanPostProcessor" />

以下是WEB-INF / globaldispatcher的代码

<context:annotation-config />
<context:component-scan base-package="net.jasonday.examples.sling.spring.mvc">
    <context:exclude-filter type="regex"
        expression="net\.jasonday\.examples\.sling\.spring\.mvc\.sling\..*" />
</context:component-scan>
<aop:aspectj-autoproxy />
<bean class="org.springframework.osgi.extensions.annotation.ServiceReferenceInjectionBeanPostProcessor" />

SlingConfiguration.java:

@Configuration
public class SlingConfiguration {
@Bean
@DependsOn("slingContextLoader")
public SlingDispatcherServlet globalSlingDispatcherServlet() {
    return new SlingDispatcherServlet();
    }
}

SlingContextLoader.java:

@Component
public class SlingContextLoader extends ContextLoader {

private ServletContext servletContext;

private ApplicationContext applicationContext;

public ApplicationContext getApplicationContext() {
    return applicationContext;
}

@Inject
public void setApplicationContext(ApplicationContext applicationContext) {
    this.applicationContext = applicationContext;
}

public ServletContext getServletContext() {
    return servletContext;
}
@ServiceReference
public void setServletContext(ServletContext servletContext) {
    this.servletContext = servletContext;
}
@Override
protected Class<?> determineContextClass(
        ServletContext currentServletContext) {
    return OsgiBundleXmlWebApplicationContext.class;
}
@Override
protected ApplicationContext loadParentContext(
        ServletContext currentServletContext) {
    return applicationContext;
}

@PostConstruct
public void init() {
    initWebApplicationContext(servletContext);
}
@PreDestroy
public void destroy() {
    closeWebApplicationContext(servletContext);
}
}

我的SlingDispatcherServlet.java

public class SlingDispatcherServlet extends DispatcherServlet implements     Servlet {
  @PreDestroy
  @Override
  public void destroy() {
super.destroy();
String attrName = getServletContextAttributeName();
getServletContext().removeAttribute(attrName);
  }
}

1 个答案:

答案 0 :(得分:2)

由于OSGi类加载问题,因为像@PostConstruct这样的Spring注释在某些时候没有按预期工作,所以会引起这个问题。

因此,解决方法是不依赖注释。以下代码为我解决了这个问题。

我在SlingContextLoader中的setServletContext()中手动调用init()方法

@ServiceReference
public void setServletContext(ServletContext servletContext) {
    log.info("in setServletContext");
    this.servletContext = servletContext;
    init();
}

在init()方法中我正在添加以下代码:

//@PostConstruct
public void init() {
    log.info("in init");
    //Remove existing application context if any
    if (servletContext
            .getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
        log.info("removing existing application context to create new one");
        closeWebApplicationContext(servletContext);
    }
    initWebApplicationContext(servletContext);
}