Статьи

Поддержка Spring Framework в REST 0.7

REST 0.7 (то есть Jersey, эталонная реализация для веб-сервисов RESTful) отсутствует и теперь включает поддержку
среды Spring . Вот пошаговый сценарий,
основанный на хорошем примере, написанном моим коллегой по Солнцу Питером Лю. В примере Питера используется среда IDE NetBeans 6.1 для создания веб-приложения, содержащего сервлет с поддержкой Spring, одноэлементный ресурс и ресурс запроса. Его пример взят из сообщения в
блоге Пола Сандоса, показывающего, как вручную интегрировать Спринг и Джерси (и до REST 0.7).

Примечание . В REST 0.8 поддержка Spring будет расширена, чтобы пользователю не приходилось создавать сервлет с поддержкой Spring.

Это пример. Для этого требуется дистрибутив NetBeans Web и Java EE 6.1 и плагин REST 0.7.

  1. Создайте проект веб-приложения и назовите его SpringRestWebApp. На странице Frameworks мастера создания проекта выберите Spring Web MVC 2.5.

  2. Щелкните правой кнопкой мыши узел SpringRestWebApp и выберите «Создать»> «Веб-службы RESTful из шаблонов». Выберите шаблон Singleton и назовите ресурс Singleton (тогда имя класса будет SingletonResource). Создайте пакет test.servlet, содержащий ресурс.

  3. Замените код в SingletonResource следующим.

    @Path("singleton")
    @Singleton
    public class SingletonResource {

    private String name;

    private int uses = 0;

    private synchronized int getCount() {
    return ++uses;
    }

    public SingletonResource() {
    name = "unset";
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    @GET
    @ProduceMime("text/plain")
    public String getDescription() {
    return "Name: " + getName() + ", Uses: " + Integer.toString(getCount());
    }
    }
  4. Щелкните правой кнопкой мыши код и выберите «Исправить импорт». Если импорт не может быть исправлен, убедитесь, что библиотеки Swing и Jersey находятся в проекте.

  5. Создайте другую веб-службу RESTful, используя шаблон Singleton. Назовите ресурс PerRequest и создайте его в том же пакете test.servlet.
  6. Замените код в PerRequestResource следующим. Нажмите правую кнопку мыши в коде и выберите Fix Imports, когда вы закончите.

    @Path("request")
    public class PerRequestResource {

    private String name;

    private int uses = 0;

    private synchronized int getCount() {
    return ++uses;
    }

    public PerRequestResource() {
    name = "unset";
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    @GET
    @ProduceMime("text/plain")
    public String getDescription() {
    return "Name: " + getName() + ", Uses: " + Integer.toString(getCount());
    }
    }
  7. Щелкните правой кнопкой мыши узел SpringRestWebApp и выберите «Создать»> «Сервлет». Назовите сервлет SpringServlet и создайте его в пакете test.servlet. Теперь вы добавили все ресурсы в проект, который должен иметь следующую структуру:

  8. Замените код в SpringServlet следующим. Щелкните правой кнопкой мыши код и выберите Fix Imports, когда закончите.

    public class SpringServlet extends ServletContainer {

    private static class SpringComponentProvider implements ComponentProvider {
    private ApplicationContext springContext;

    SpringComponentProvider(ApplicationContext springContext) {
    this.springContext = springContext;
    }

    private String getBeanName(Class c) {
    String names[] = springContext.getBeanNamesForType(c);
    if (names.length == 0) {
    return null;
    } else if (names.length > 1) {
    throw new RuntimeException("Multiple configured beans for "
    + c.getName());
    }
    return names[0];
    }

    public Object getInstance(Scope scope, Class c)
    throws InstantiationException, IllegalAccessException {
    String beanName = getBeanName(c);
    if (beanName == null) return null;

    if (scope == Scope.WebApplication &&
    springContext.isSingleton(beanName)) {
    return springContext.getBean(beanName, c);
    } else if (scope == Scope.ApplicationDefined &&
    springContext.isPrototype(beanName) &&
    !springContext.isSingleton(beanName)) {
    return springContext.getBean(beanName, c);
    } else {
    return null;
    }
    }

    public Object getInstance(Scope scope, Constructor contructor,
    Object[] parameters)
    throws InstantiationException, IllegalArgumentException,
    IllegalAccessException, InvocationTargetException {
    return null;
    }

    public Object getInjectableInstance(Object instance) {
    return instance;
    }

    public void inject(Object instance) {
    }
    };

    @Override
    protected void initiate(ResourceConfig rc, WebApplication wa) {
    ApplicationContext springContext = WebApplicationContextUtils.
    getRequiredWebApplicationContext(getServletContext());

    wa.initiate(rc, new SpringComponentProvider(springContext));
    }
    }

    Пол Сандос пишет: «Обратите внимание, что SpringServlet расширяет ServletContainer и метод initiate переопределяется. Этот метод создает ApplicationContext, а затем инициирует WebApplication, передавая экземпляр статического внутреннего класса SpringComponentProvider. Этот класс реализует ComponentProvider, а метод getInstance попытается получить Spring bean-компонент, который присутствует и соответствует запрошенной области действия; если это так, то возвращается экземпляр bean-компонента, в противном случае возвращается null. (Обратите внимание, что метод getInstance с параметром типа Constructor не реализован, это потому, что мы не определили, как поддерживать конструкторы с бобами Spring)

  9. Разверните узел Веб-страницы проекта> WEB-INF. Откройте файл web.xml проекта. Замените com.sun.ws.rest.impl.container.servlet.ServletAdaptor на test.servlet.SpringServlet .
  10. Добавьте следующее в файл applicationContext.xml проекта, чтобы инициализировать ресурсы:
    <bean id="bean1" scope="singleton" class="test.servlet.SingletonResource">
    <property name="name" value="Mr. Singleton Bean"/>
    </bean>
    <bean id="bean2" scope="prototype" class="test.servlet.PerRequestResource">
    <property name="name" value="Mr. PerRequest Bean"/>
    </bean>
  11. Щелкните правой кнопкой мыши узел проекта и выберите Test RESTful Web Services. Среда IDE развертывает проект и запускает тестер службы RESTful в окне браузера.

Когда вы проверяете путь Singleton, служба возвращает свойство Mr. Singleton Bean и значение Uses увеличивается для каждого запроса. Когда вы проверяете путь PerRequest, служба возвращает свойство Bean-компонента Mr. PerRequest, и значение Uses не увеличивается.