Ответ 1
Стандарт JAX-RS использует Application
качестве класса конфигурации. ResourceConfig
расширяет Application
.
Существует три основных способа (в контейнере сервлетов) настроить Джерси (JAX-RS):
- Только с web.xml
- Как с web.xml, так и с классом
Application/ResourceConfig
- Только с классом
Application/ResourceConfig
аннотированным@ApplicationPath
.
Только с web.xml
Можно настроить приложение стандартным способом JAX-RS, но следующее характерно для Джерси
<web-app>
<servlet>
<servlet-name>jersey-servlet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.mypackage.to.scan</param-value>
</init-param>
</servlet>
...
<servlet-mapping>
<servlet-name>jersey-servlet</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
...
</web-app>
Поскольку Jersey запускается в контейнере сервлетов, то совершенно верно, что приложение Jersey работает как сервлет. Сервлет Джерси, который обрабатывает входящие запросы, является ServletContainer
. Итак, здесь мы объявляем его как <servlet-class>
. Мы также настраиваем <init-param>
сообщая Джерси, какой пакет сканировать для наших @Path
и @Provider
чтобы он мог их зарегистрировать.
На самом деле Джерси создаст экземпляр ResourceConfig
, который используется для настройки приложения. Затем он зарегистрирует все классы, обнаруженные при сканировании пакета.
Как с web.xml, так и с Application/ResourceConfig
Если мы хотим программно настроить наше приложение с подклассом Application
или ResourceConfig
, мы можем сделать это с одним изменением в приведенном выше файле web.xml. Вместо того, чтобы устанавливать init-param для сканирования пакетов, мы используем init-param для объявления нашего подкласса Application/ResourceConfig
.
<servlet>
<servlet-name>jersey-servlet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.example.JerseyApplication</param-value>
</init-param>
<servlet-mapping>
<servlet-name>jersey-servlet</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
</servlet>
package com.example;
public class JerseyApplication extends ResourceConfig {
public JerseyApplication() {
packages("com.abc.jersey.services");
}
}
Здесь мы настраиваем init-param
javax.ws.rs.Application
с полным именем нашего подкласса ResourceConfig
. И вместо того, чтобы использовать init-param
который сообщает Джерси, какой пакет нужно сканировать, мы просто используем вспомогательный метод packages()
ResourceConfig
.
Мы также могли бы использовать методы register()
и property()
для регистрации ресурсов и поставщиков, а также для настройки свойств Джерси. С помощью метода property()
все, что можно настроить как init-param
, также можно настроить с помощью метода property()
. Например, вместо вызова packages()
, мы могли бы сделать
public JerseyApplication() {
property("jersey.config.server.provider.packages",
"com.mypackage.to.scan");
}
Только с Application/ResourceConfig
Без web.xml Джерси нужен способ предоставить нам отображение сервлетов. Мы делаем это с @ApplicationPath
аннотации @ApplicationPath
.
// 'services', '/services', or '/services/*'
// is all the same. Jersey will change it to be '/services/*'
@ApplicationPath("services")
public class JerseyApplication extends ResourceConfig {
public JerseyApplication() {
packages("com.abc.jersey.services");
}
}
Здесь с @ApplicationPath
, это так же, как если бы мы настроили отображение сервлета в web.xml
<servlet-mapping>
<servlet-name>JerseyApplication</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
При использовании только Java-кода для конфигурации у Джерси должен быть какой-то способ обнаружить наш класс конфигурации. Это делается с использованием ServletContanerInitializer
. Это то, что было представлено в спецификации Servlet 3.0, поэтому мы не можем использовать конфигурацию "только Java" в более ранних контейнерах сервлетов.
В основном происходит то, что разработчик инициализатора может сообщить контейнеру сервлета, какие классы искать, и контейнер сервлета передаст эти классы onStartup()
инициализатора onStartup()
. В реализации - Джерси инициализатора, Джерси настраивает его искать Application
классов и классы, аннотированные @ApplicationPath
. Смотрите этот пост для дальнейшего объяснения. Поэтому, когда контейнер сервлета запускает приложение, инициализатор Джерси будет передан нашему классу Application/ResourceConfig
.
Что я могу сделать внутри подкласса ResourceConfig
Просто посмотрите на Javadoc. В основном это просто регистрация классов. Не так много, что вам нужно сделать с этим. Основными методами, которые вы будете использовать, являются методы register()
, packages()
и property()
. Метод register()
позволяет вручную регистрировать классы и экземпляры ресурсов и поставщиков. Метод packages()
, рассмотренный ранее, перечисляет пакеты, которые вы хотите, чтобы Джерси сканировал для @Path
и @Provider
и регистрировал их для вас. А метод property()
позволяет вам установить некоторые настраиваемые свойства 1.
ResourceConfig
- это просто удобный класс. Помните, это расширяет Application
, поэтому мы могли бы даже использовать стандартный класс Application
@ApplicationPath("/services")
public class JerseyApplication extends Application {
@Override
public Set<Class<?>> getClasses() {
final Set<Class<?>> classes = new HashSet<>();
classes.add(MyResource.class);
return classes;
}
@Override
public Set<Object> getSingletons() {
final Set<Object> singletons = new HashSet<>();
singletons.add(new MyProvider());
return singletons;
}
@Override
public Map<String, Object> getProperties() {
final Map<String, Object> properties = new HashMap<>();
properties.put("jersey.config.server.provider.packages",
"com.mypackage.to.scan");
return properties;
}
}
С ResourceConfig
мы бы просто
public class JerseyApplication extends ResourceConfig {
public JerseyApplication() {
register(MyResource.class);
register(new MyProvider());
packages("com.mypackages.to.scan");
}
}
Помимо удобства, есть еще несколько вещей, которые помогают Джерси настроить приложение.
Экологическая среда
Все приведенные выше примеры предполагают, что вы работаете в установленной серверной среде, например Tomcat. Но вы также можете запустить приложение в среде SE, где вы запускаете встроенный сервер и запускаете приложение из main
метода. Иногда вы будете видеть эти примеры при поиске информации, поэтому я хочу показать, как это выглядит, так что, когда вы все сталкиваетесь с этим, вы не удивляетесь и не знаете, как она отличается от ваших настроек.
Так что иногда вы увидите пример, как
ResourceConfig config = new ResourceConfig();
config.packages("com.my.package");
config.register(SomeFeature.class);
config.property(SOME_PROP, someValue);
Скорее всего, здесь происходит то, что в примере используется встроенный сервер, такой как Grizzly. Остальная часть кода для запуска сервера может быть что-то вроде
public static void main(String[] args) {
ResourceConfig config = new ResourceConfig();
config.packages("com.my.package");
config.register(SomeFeature.class);
config.property(SOME_PROP, someValue);
String baseUri = "http://localhost:8080/api/";
HttpServer server = GrizzlyHttpServerFactory
.createHttpServer(URI.create(baseUri), config);
server.start();
}
Таким образом, в этом примере запускается автономный сервер, а ResourceConfig
используется для настройки Джерси. Здесь и от предыдущих примеров отличается то, что в этом примере мы не расширяем ResourceConfig
, а просто создаем его экземпляр. Ничего не изменилось бы, если бы мы
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
packages("com.my.package");
register(SomeFeature.class);
property(SOME_PROP, someValue);
}
}
HttpServer server = GrizzlyHttpServerFactory
.createHttpServer(URI.create(baseUri), new JerseyConfig());
Скажем, вы проходили какое-то руководство, и оно показало конфигурацию для автономного приложения, где они создают экземпляр ResourceConfig
, но вы запускаете свое приложение в контейнере сервлета и используете более раннюю конфигурацию, в которой вы расширяете ResourceConfig
. Ну, теперь вы знаете, в чем разница и какие изменения вам нужно внести. Я видел людей, делающих действительно странные вещи, потому что они не понимали эту разницу. Например, я видел, как кто-то создает экземпляр ResourceConfig
внутри класса ресурса. Вот почему я добавил этот маленький кусочек; так что вы не делаете ту же ошибку.
Сноски
1. Существует ряд различных настраиваемых свойств.Ссылка на ServerProperties
- это лишь некоторые общие свойства.Есть также различные свойства, связанные с конкретными функциями.В документации должны быть упомянуты эти свойства в разделе документации, относящейся к этой функции.Для получения полного списка всех настраиваемых свойств вы можете посмотреть все константы Джерси и найти те, в которых строковое значение начинается с jersey.config
.Если вы используете web.xml, вы должны использовать строковое значение в качестве имени параметра init-param
param-name
.Если вы используете конфигурацию Java (ResourceConfig
), то вы бы вызвали property(ServerProperties.SOME_CONF, value)