Как установить 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, не может быть разрешен.