Как установить OsgiBundleXmlApplicationContext в качестве родительского для WebApplicationContext

В моем приложении Camel (2.14.0) я использую Spring Web Services для запуска маршрутов Camel. Артефакт построен в виде пакета OSGi и развернут в Karaf (3.0.2).

Для первой версии я настроил Spring-W для использования внутреннего веб-сервера JVM через org.springframework.remoting.support.SimpleHttpServerFactoryBean выставить веб-сервис. Это работает просто отлично. Но это не очень OSGi-иш. Поэтому вместо этого я хотел бы опубликовать org.springframework.ws.transport.http.MessageDispatcherServlet в качестве услуги для расширителя доски Karaf, например:

<bean id="pas-ws-patient-servlet" class="org.springframework.ws.transport.http.MessageDispatcherServlet">
    <property name="contextConfigLocation" value="/endpoint-mapping.xml" /> 
</bean>

<osgi:service ref="pas-ws-patient-servlet" interface="javax.servlet.http.HttpServlet">
    <service-properties>
        <entry key="alias" value="/${pas.ws.patient.contextroot}" />
    </service-properties>
</osgi:service>

Который работает как шарм для "обычных" сервлетов. Но MessageDispatcherServlet хочет построить свой собственный WebApplicationContext и ожидает найти боб типа org.springframework.ws.server.EndpointMapping в этом контексте. Верблюд обеспечивает реализацию EndpointMapping это должно использоваться с его компонентом spring-ws.

Проблема, с которой я сталкиваюсь, заключается в том, что один и тот же экземпляр компонента отображения конечной точки должен быть совместно использован OsgiBundleXmlApplicationContext который создает контекст Camel и контекст приложения, созданный MessageDispatcherServlet, Что было бы, если бы мой OsgiBundleXmlApplicationContext был родителем WebApplicationContext, Хотя, как установить родительский контекст WebApplicationContext в "текущий" контекст, из которого я публикую сервлет как сервис, ускользает от меня.

Создание WebApplicationContext изнутри OsgiBundleXmlApplicationContext передать его в MessageDispatcherServlet дает мне исключение:

java.lang.IllegalArgumentException: Cannot resolve ServletContextResource without ServletContext

К сожалению WebServiceMessageReceiver (который заключает в капсулу EndpointMapping) из MessageDispatcherServlet является частным членом. Таким образом, я не могу установить bean-компонент отображения напрямую.

Есть ли способ создать контекстную иерархию? Или же экземпляр компонента может быть передан по контекстам другим способом?

1 ответ

Решение

Решение на самом деле прямо и задокументировано в JavaDoc FrameworkServlet, который MessageDispatcherServlet продолжается:

Можно установить ApplicationContextInitializer на MessageDispatcherServlet. Используйте инициализатор контекста, чтобы установить текущий контекст приложения в качестве родителя контекста приложения сервлета. Для этого вы должны также реализовать ApplicationContextAware интерфейс, чтобы получить текущий контекст (OsgiBundleXmlApplicationContext в этом случае). Затем зарегистрируйте сервлет как сервис:

<!-- This bean sets our current context as the parent context of the XmlWebApplicationContext 
    that the MessageDispatcherServlet insists on creating. -->
<bean id="springWsContextInitializer" class="x.x.x.SpringWsContextInitializer" />

<bean id="spring-ws-servlet" class="org.springframework.ws.transport.http.MessageDispatcherServlet">
    <!-- We inherit all beans from the current context, so no need to specify a separate context file. -->
    <property name="contextConfigLocation" value="" />
    <property name="ContextInitializers" ref="springWsContextInitializer" />
</bean>

<osgi:service ref="spring-ws-servlet" interface="javax.servlet.http.HttpServlet">
    <service-properties>
        <entry key="alias" value="/${servlet.contextroot}" />
        <entry key="servlet-name" value="spring-ws-servlet" />
    </service-properties>
</osgi:service>

Класс инициализатора контекста:

public class SpringWsContextInitializer implements ApplicationContextInitializer<XmlWebApplicationContext>, ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void initialize(XmlWebApplicationContext applicationContext) {
        applicationContext.setParent(this.applicationContext);
    }
}

Чтобы заставить то же самое работать, используя blueprint вместо spring-dw, мне нужно было изменить SpringWsContextInitializer так:

public class SpringWsContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

    private final EndpointMapping endpointMapping;

    public SpringWsContextInitializer(final EndpointMapping endpointMapping) {
        this.endpointMapping = endpointMapping;
    }

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        StaticApplicationContext parentContext = new StaticApplicationContext();
        parentContext.refresh();
        parentContext.getDefaultListableBeanFactory().registerSingleton("endpointMapping", this.endpointMapping);
        applicationContext.setParent(parentContext);
    }
}

Должна быть возможность публиковать bean-компонент отображения конечной точки в качестве службы OSGi, а затем ссылаться на bean-компонент службы в файле контекста для сервлета, но обработчик пространства имен OSGi для пространства имен OSGi, необходимый для файла контекста Spring, не может быть разрешен.

Другие вопросы по тегам