Последние несколько дней я работал над переносом приложения с JBoss 4 на Wildfly 8 . В приложении используются разные технологии, но мы сосредоточимся здесь на XML Web Services, JAX-WS . Да, я знаю, что они больше не модные, но они были разработаны давно и должны быть сохранены для проблем совместимости.
В любом случае, путь для миграции этих сервисов был не так прост. Я делюсь некоторыми проблемами и исправлениями с надеждой, что они могут помочь другим разработчикам, столкнувшимся с такими же проблемами.
Пример определения
Вот пример определения Web-сервиса в старой системе, JBoss 4:
|
1
2
3
4
5
6
|
@javax.jws.WebService(endpointInterface = "some.pack.age.WebService")@javax.jws.soap.SOAPBinding(style = SOAPBinding.Style.DOCUMENT)@org.jboss.ws.annotation.EndpointConfig(configName = "Standard WSSecurity Endpoint")@javax.jws.HandlerChain(file = "handlers.xml")@org.jboss.ws.annotation.SchemaValidation(enabled = true, errorHandler = CustomErrorHandler.class)public class WebServiceImpl implements WebService { |
К счастью, большая часть определения использует стандартные аннотации Java EE. Только @org.jboss.ws.annotation.EndpointConfig и @org.jboss.ws.annotation.SchemaValidation взяты из старых библиотек JBossWS.
Мы можем легко избавиться от @org.jboss.ws.annotation.EndpointConfig так как он нам не понадобится в новом приложении. Для справки: он используется для установки дополнительных данных конфигурации, которые должны быть предварительно определены с конечной точкой. Проверьте документацию Предопределенные конфигурации клиента и конечной точки .
Мы хотим сохранить @org.jboss.ws.annotation.SchemaValidation . Для справки, эта аннотация проверяет входящие и исходящие сообщения SOAP по соответствующей схеме в контракте wsdl конечной точки. Поскольку аннотации больше не существует в JBossWS, мы должны использовать Apache CXF , который является базовой реализацией для JAX-WS на Wildfly .
Проблемы
Вот несколько проблем, с которыми я столкнулся:
СхемаВалидация Аннотация
Аннотация @org.jboss.ws.annotation.SchemaValidation больше не существует. Вы должны использовать аннотацию org.apache.cxf.annotations.SchemaValidation из Apache CXF .
Добавьте следующую зависимость Maven для использования аннотации Apache CXF :
|
1
2
3
4
5
6
|
<dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-api</artifactId> <version>2.7.11</version> <scope>provided</scope></dependency> |
Также обратите внимание, что в исходной аннотации мы можем определить свойство errorHandler . Старое приложение использовало пользовательский обработчик ошибок для установки пользовательского сообщения об ошибках проверки схемы. В новой аннотации нет эквивалента, поэтому нам нужно сделать это по-другому. Для воспроизведения старого поведения я использовал Apache CXF Interceptors . Создайте класс-перехватчик и расширьте AbstractPhaseInterceptor . Вот образец:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
public class SchemaValidationErrorInterceptor extends AbstractPhaseInterceptor<Message> { public SchemaValidationErrorInterceptor() { super(Phase.MARSHAL); } @Override public void handleMessage(Message message) throws Fault { Fault fault = (Fault) message.getContent(Exception.class); Throwable cause = fault.getCause(); while (cause != null) { if (cause instanceof SAXParseException) { fault.setMessage("Invalid XML: " + fault.getLocalizedMessage()); break; } cause = cause.getCause(); } }} |
И вы можете использовать это так:
|
1
2
3
|
@org.apache.cxf.interceptor.OutFaultInterceptors( classes = SchemaValidationErrorInterceptor.class) |
Перехватчики используются как клиентами CXF, так и серверами CXF . Существуют входящие и исходящие цепочки перехватчиков, выполняемые для регулярной обработки, а также при возникновении ошибки. В этом случае мы хотим переопределить сообщение проверки схемы, поэтому нам нужно связать наш перехватчик в цепочке исходящих перехватчиков с ошибкой. Вы можете использовать аннотацию @OutFaultInterceptors для этого поведения. Каждая цепочка разбита на фазы. Вы определяете этап, на котором вы хотите, чтобы перехватчик запускался, передавая Phase.MARSHAL в конструктор. Существуют и другие фазы, но поскольку мы хотим изменить сообщение об ошибке, мы делаем это на этапе MARSHAL .
Разные WSDL
В старых веб-службах файл WSDL создавался автоматически во время развертывания. К сожалению, в некоторых ситуациях WSDL, сгенерированный JBoss 4 и Wildfly 8 , отличается. Это может вызвать проблемы с вашими внешними абонентами. В этом случае основная проблема заключалась в проверке схемы. Запросы, которые были действительны в JBoss 4, больше не действовали, когда выполнялись в Wildfly 8 .
Причина такого поведения была в целевых пространствах имен. Если вы используете аннотации @XmlRootElement pojos в своих параметрах веб-службы без определения свойства namespace в аннотации, JBoss 4 WS сгенерировал целевой элемент WSDL с черным пространством имен. Apache CXF будет использовать пространство имен по умолчанию веб-службы для привязки элементов WSDL, если они пустые. Для справки это делается в коде CXF: org.apache.cxf.jaxws.support.JaxWsServiceConfiguration#getParameterName .
Это можно исправить, изменив код CXF , но мы решили поместить старый сгенерированный файл WSDL в перенесенные источники приложений и включить его в дистрибутив. Это больше не генерируется автоматически, это означает, что нам нужно вручную генерировать WSDL, если мы изменим API. Мы должны быть осторожны, чтобы убедиться, что мы ничего не нарушаем в WSDL. Этот подход казался лучше, чем поддержка собственной версии CXF . Возможно, мы могли бы также исправить это, но мы считаем, что поведение JBoss 4 не было предназначено.
Запустить CXF
Чтобы использовать конкретные API из CXF , недостаточно иметь зависимость проекта от него. Фактически, первые несколько раз, когда я пытался внести изменения, казалось, ничего не связанного с CXF . Это происходит потому, что Wildfly ищет только стандартные аннотации Java EE JAX-WS . Чтобы все поведение CXF работало, мы должны сообщить Wildfly, что наше приложение зависит от CXF , даже если библиотеки уже находятся на сервере. Да, это немного сбивает с толку.
Приложение развернуто в файле EAR. Поэтому вам нужно создать jboss-deployment-structure.xml и добавить следующее содержимое:
|
1
2
3
4
5
6
7
8
9
|
<jboss-deployment-structure> <sub-deployment name="application.war"> <dependencies> <module name="org.apache.cxf"/> </dependencies> </sub-deployment></jboss-deployment-structure> |
Использование файла MANIFEST.MF в файле WAR, очевидно, не работает, если он развернут в файле EAR. Для получения дополнительной информации, пожалуйста, проверьте Class Loading в WildFly .
Если вы хотите использовать другие функции CXF , особенно те, которые связаны с Spring, все может быть немного сложнее. Загляните в этот пост: разные факты о JBoss. Факт 6: JBoss и CXF: матч, заключенный на небесах .
Окончательное определение
Это должно быть нашим окончательным определением для нашего веб-сервиса:
|
1
2
3
4
5
6
7
8
9
|
@WebService( wsdlLocation = "WebService.wsdl", endpointInterface = "some.pack.age.WebService")@SOAPBinding(style = SOAPBinding.Style.DOCUMENT)@HandlerChain(file = "/handlers.xml")@SchemaValidation(type = SchemaValidation.SchemaValidationType.IN)@OutFaultInterceptors(classes = SchemaValidationErrorInterceptor.class)public class WebServiceImpl implements BDNSWebService { |
Как видите, необходимые изменения для переноса веб-службы с JBoss 4 на Wildfly — это всего лишь несколько. Тем не менее, есть несколько мелких деталей, которые могут блокировать вас на долгое время, если вы не знаете детали. Может быть, у вас другая настройка и проблемы, с которыми вы сталкиваетесь, другие. Это также может помочь, если вы просто пытаетесь настроить CXF с Wildfly. Надеюсь, этот пост будет вам полезен.
| Ссылка: | Wildfly, Apache CXF и @SchemaValidation от нашего партнера по JCG Роберто Кортеса в блоге |