Статьи

Запуск Spring MVC веб-приложений в OSGi

Последние пару недель я занимаюсь разработкой веб-приложения, которое развертывается в контейнер OSGi (Equinox) и использует поддержку Spring DM Spring MVC . Первое, что я обнаружил, было то, что аннотации Spring MVC не были поддержаны в выпуске M1. По-видимому, это было вызвано ошибкой в Spring 2.5.3, а не Spring DM. Поскольку Spring DM 1.1.0 M2 был выпущен вместе с Spring 2.5.4 сегодня , я думаю, что это сейчас исправлено.

Ниже рассказывается о моем опыте установки и запуска приложения Spring MVC в Equinox 3.2.2, Jetty 6.1.9 и Spring DM 1.1.0 M2 SNAPSHOT (с прошлой недели). Если вы хотите узнать больше о том, почему Spring MVC + OSGi — это круто, см. Статью о веб-приложениях и OSGi от Costin Leau .

Чтобы получить простое приложение Spring World для Hello World, работающее в OSGi, нужно выполнить pre style = «overflow: auto;» tty easy. Сложной частью является настройка контейнера со всеми установленными и запущенными пакетами Spring и Jetty. Я полагаю, SSAP может решить эту проблему. К счастью для меня, это сделал другой член моей команды.

После того, как вы это сделаете, просто создайте файл MANIFEST.MF для вашей WAR, который содержит правильную информацию для распознавания OSGi. Ниже приводится тот, который я использовал, когда впервые попытался заставить свое приложение работать.

Manifest-Version: 1
Bundle-ManifestVersion: 2
Spring-DM-Version: 1.1.0-m2-SNAPSHOT
Spring-Version: 2.5.2
Bundle-Name: Simple OSGi War
Bundle-SymbolicName: myapp
Bundle-Classpath: .,WEB-INF/classes,WEB-INF/lib/freemarker-2.3.12.jar,
WEB-INF/lib/sitemesh-2.3.jar,WEB-INF/lib/urlrewritefilter-3.0.4.jar,
WEB-INF/lib/spring-beans-2.5.2.jar,WEB-INF/lib/spring-context-2.5.2.jar,
WEB-INF/lib/spring-context-support-2.5.2.jar,WEB-INF/lib/spring-core-2.5.2.jar,
WEB-INF/lib/spring-web-2.5.2.jar,WEB-INF/lib/spring-webmvc-2.5.2.jar
Import-Package: javax.servlet,javax.servlet.http,javax.servlet.resources,javax.swing.tree,
javax.naming,org.w3c.dom,org.apache.commons.logging,javax.xml.parsers;resolution:=optional,
org.xml.sax;resolution:=optional,org.xml.sax.helpers;resolution:=optional

В идеале вы можете сгенерировать этот файл MANIFEST.MF, используя maven-bundle-plugin . Тем не менее, он не поддерживает WAR в своей версии 1.4.0.

Вы можете видеть, что это приложение, которое использует Spring MVC, FreeMarker, SiteMesh и URLRewriteFilter. Вы должны иметь возможность скачать его , разархивировать, запустить «пакет mvn» и установить его в Equinox, используя «install file: // <path to war>».

Это все прекрасно, но не дает никаких преимуществ OSGi. Эта установка прекрасно работает, пока вы не попытаетесь импортировать службы OSGi, используя файл контекста с элементом <osgi: reference> . После добавления такой ссылки, вероятно, вы получите следующую ошибку:

SEVERE: 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]

Чтобы это исправить, добавьте следующее в ваш web.xml (если вы используете ContextLoaderListener, как <init-параметр> в DispatcherServlet, если вы не):

  <context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicationContext</param-value>
</context-param>

После этого вы можете получить следующую ошибку при запуске:

SEVERE: Context initialization failed
org.springframework.context.ApplicationContextException: Custom
context class [org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicationContext]
is not of type [org.springframework.web.context.ConfigurableWebApplicationContext]

Чтобы исправить это, я переключаюсь с ссылок на JAR-файлы Spring в WEB-INF / lib на импорт пакетов для Spring (которые уже были установлены в моем контейнере Equinox).

Bundle-Classpath: .,WEB-INF/classes,WEB-INF/lib/freemarker-2.3.12.jar,
WEB-INF/lib/sitemesh-2.3.jar,WEB-INF/lib/urlrewritefilter-3.0.4.jar
Import-Package:
javax.servlet,javax.servlet.http,javax.servlet.resources,javax.swing.tree,
javax.naming,org.w3c.dom,org.apache.commons.logging,javax.xml.parsers;resolution:=optional,
org.xml.sax;resolution:=optional,org.xml.sax.helpers;resolution:=optional,
org.springframework.osgi.web.context.support,
org.springframework.context.support,
org.springframework.web.context,
org.springframework.web.context.support,
org.springframework.web.servlet,
org.springframework.web.servlet.mvc,
org.springframework.web.servlet.mvc.support,
org.springframework.web.servlet.view,
org.springframework.ui,
org.springframework.web.servlet.view.freemarker

После восстановления моей WAR и перезагрузки пакета в Equinox я столкнулся со следующим сообщением об ошибке:

SEVERE: Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'freemarkerConfig' defined in ServletContext
resource [/WEB-INF/myapp-servlet.xml]: Instantiation of bean failed;
nested exception is java.lang.NoClassDefFoundError:
freemarker/cache/TemplateLoader
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:851)

Насколько я могу судить, это потому, что версия Spring MVC, установленная в Equinox, не может разрешить JAR FreeMarker в моем каталоге WEB-INF / lib.

Чтобы доказать, что я не схожу с ума, я закомментировал свои bean-компоненты «freemarkerConfig» и «viewResolver» в myapp-servlet.xml и изменил их на обычный InternalResourceViewResolver:

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="pre style="overflow: auto;"fix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>

Это сработало, и я смог успешно увидеть «Hello World» из JSP в моем браузере. FreeMarker / SiteMesh тоже работал, но FreeMarker не работал как View для Spring MVC.

Чтобы попытаться решить эту проблему, я создаю пакет для FreeMarker с помощью «java -jar bnd-0.0.249.jar wrap freemarker-2.3.12.jar» и устанавливаю его в Equinox. Затем я изменяю свой MANIFEST.MF, чтобы использовать импорт FreeMarker вместо ссылки на JAR в WEB-INF / lib.

Bundle-Classpath:
.,WEB-INF/classes,WEB-INF/lib/sitemesh-2.3.jar,WEB-INF/lib/urlrewritefilter-3.0.4.jar
Import-Package:
javax.servlet,javax.servlet.http,javax.servlet.resources,javax.swing.tree,
javax.naming,org.w3c.dom,org.apache.commons.logging,javax.xml.parsers;resolution:=optional,
org.xml.sax;resolution:=optional,org.xml.sax.helpers;resolution:=optional,
org.springframework.osgi.web.context.support,
org.springframework.context.support,
org.springframework.web.context,
org.springframework.web.context.support,
org.springframework.web.servlet,
org.springframework.web.servlet.mvc,
org.springframework.web.servlet.mvc.support,
org.springframework.web.servlet.view,
org.springframework.ui,
org.springframework.web.servlet.view.freemarker,
freemarker.cache,freemarker.core,freemarker.template,freemarker.ext.servlet

К сожалению, это все еще не работает, и я все еще не смог заставить FreeMarker работать с Spring MVC в OSGi. Сумасшедшая вещь, я действительно решил это однажды неделю назад. Вскоре после этого я восстановил «Равноденствие» с нуля, и с тех пор я бился головой об стену из-за этой проблемы. На прошлой неделе я обнаружил проблему в JIRA Spring , но решил, что исправлю ее несколько часов спустя.

Я загрузил окончательный проект, который не работает, по следующему URL:

http://static.raibledesigns.com/downloads/myapp-osgi.zip

Если вы хотите, чтобы этот проект работал с Spring MVC + JSP, просто измените myapp-servlet.xml, чтобы удалить ссылки FreeMarker, и вместо этого используйте InternalResourceViewResolver.

Я надеюсь, что Spring DM + Spring MVC поддерживает больше, чем просто JSP, как технологию просмотра. Я надеюсь, что не смогу заставить FreeMarker работать из-за некоторого недосмотра с моей стороны. Если у вас есть приложение Spring DM + Spring MVC, работающее с Velocity или FreeMarker, я бы хотел услышать об этом.