Загрузка spring dm в контейнер OSGi

Я пытаюсь загрузить spring dm в свой пакет OSGi. Я следовал руководству. Моя цель состоит в том, чтобы для определенного URL-адреса URL-адрес должен обрабатываться Spring вместо сервлета sling по умолчанию. Я частично преуспеваю в достижении того же самого.

Иногда это не работает. Мой сервлет globaldispatcher не инициализируется. Проблема возникает периодически. Иногда мой весенний сервлет инициализируется просто отлично. Но иногда я получаю эту ошибку:

[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

Я использую следующие зависимости, как указано в учебнике: (Все это пакеты 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>

Below is the code from 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);
  }
}

person Prashant Onkar    schedule 01.09.2015    source источник
comment
Одна вещь, которую я примерно узнал об этой проблеме, это то, что мой метод init() (который аннотирован как @PostConstruct) не вызывается. Я подозреваю, что ни один из моих весенних аннотированных методов не вызывается так, как ожидалось.   -  person Prashant Onkar    schedule 03.09.2015


Ответы (1)


Эта проблема вызвана тем, что аннотации Spring, такие как @PostConstruct, иногда не работают должным образом из-за проблем с загрузкой классов OSGi.

Следовательно, обходным путем было бы не полагаться на аннотации. Приведенный ниже код решил проблему для меня.

Я вызываю метод init() вручную в setServletContext() в SlingContextLoader

@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);
}
person Prashant Onkar    schedule 08.09.2015
comment
Отличный обходной путь! Вызов @PostConstruct — настоящая боль в OSGi для Spring. - person Denis Kalinin; 16.05.2016