Избавьтесь от *-portlet.xml, используя аннотации. Возможный? Как?

Документация здесь говорит:

Фреймворк при инициализации DispatcherPortlet ищет файл с именем [portlet-name]-portlet.xml в каталоге WEB-INF вашего веб-приложения и создает определенные bean-компоненты (переопределяя определения любых bean-компонентов, определенных с помощью то же имя в глобальном масштабе).

Я делаю настройку, используя аннотации, если могу, потому что легче поддерживать синхронизацию конфигурации и фактического кода. Итак, этот [portlet-name]-portlet.xml в моем проекте выглядит следующим образом (и этот файл существует раз в год... Один для каждого портлета):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:annotation-config />
    <bean class="some.path.to.a.Class" />
</beans>

Это много XML только для крошечной информации: этот some.path.to.a.Class должен использоваться для обработки запросов к [portlet-name]. Было бы намного проще поместить аннотацию @ForPortlet("[portlet-name]") или что-то в этом роде в some.path.to.a.Class и полностью забыть об этом XML-файле. Возможно ли что-нибудь подобное? Этот отчет об ошибке может указывать на "нет"/"еще нет"?

РЕШЕНИЕ

Благодаря супер полезным советам от OlliS (большое спасибо!) Я нашел способ сделать это. Я погрузился в моменты, которые OlliS дал мне в источник Spring, и, потратив много времени, чтобы выяснить, как все работает вместе, я написал следующий класс:

public class MyPortletContext extends
            AbstractRefreshablePortletApplicationContext
    {
        private static final String PORTLET_PACKAGE = "package.where.my.portlets.are.";
        private static final String REMOVE_FROM_NAMESPACE_FOR_PORTLETNAME = "-portlet";

    @Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
            throws BeansException, IOException
    {
        // The following line does the same thing as specifying
        // <context:annotation-config /> in the xml file:
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);

        // Figure out the portlet name:
        final String portletName = StringUtils.removeEnd(getNamespace(),
                REMOVE_FROM_NAMESPACE_FOR_PORTLETNAME);
        // Derive the controller from the portlet name:
        final String beanClassName = PORTLET_PACKAGE + portletName;

        // Tell spring about the bean:
        final GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClassName(beanClassName);

        final String beanName = BeanDefinitionReaderUtils.generateBeanName(
                beanDefinition, beanFactory);

        final BeanDefinitionHolder bdHolder = new BeanDefinitionHolder(
                beanDefinition, beanName, new String[] { beanClassName });

        BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, beanFactory);
    }

}

Затем я зарегистрировал этот класс как contextClass в файле portlet.xml, используя init-param, как это сделал ОллиС в своем ответе. И это все. Файл *-portlet.xml больше не требуется. Всего один класс, настраивающий все мои портлеты.

Конечно, можно еще улучшить этот класс, сделав его более гибким, читая пакет портлета откуда-то вместо константы. Может быть, init-param. Или можно искать аннотации, возможно, упомянутую аннотацию @ForPortlet, которая создаст возможность зарегистрировать более одного компонента. Но пока я счастлив:-).

1 ответ

Решение

Вы пытались использовать аннотированные классы @Configuration для настройки? Это фича в весеннем фреймворке начиная с версии 3.0

Смотрите справочную документацию здесь:

http://static.springsource.org/spring/docs/3.0.x/reference/beans.html

Например, context:component-scan может быть расширен:

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.scan("com.acme");

Конфигурация на основе Java также может быть объединена с XML; упоминается в документации.

Надеюсь, поможет.

РЕДАКТИРОВАТЬ: Таким образом, вы хотели бы заменить конкретный контекст портлета с классом Java. Я не уверен, что DispatcherPortlet поддерживает настройку Java, хотя. Вы можете попробовать добавить что-то вроде этого, которое используется в обычных веб-приложениях:

<portlet>
    <portlet-name>portlet</portlet-name>
    <portlet-class>org.springframework.web.portlet.DispatcherPortlet</portlet-class>
<init-param>
 <!-- Configure DispatcherPortlet to use AnnotationConfigWebApplicationContext
       instead of the default XmlPortletApplicationContext ? -->
      <param-name>contextClass</param-name>
      <param-value>
          org.springframework.web.context.support.AnnotationConfigWebApplicationContext
      </param-value>
</init-param>
<init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>com.acme.web.PortletConfig</param-value>
  </init-param>
<!-- ... -->
</portlet>

Некоторая документация по AnnotationConfigWebApplicationContext: http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/context/support/AnnotationConfigWebApplicationContext.html

Из справочной документации портлета:

Параметры инициализации DispatcherPortlet

contextClass

Класс, реализующий WebApplicationContext, который будет использоваться для создания экземпляра контекста, используемого этим портлетом. Если этот параметр не указан, будет использован XmlPortletApplicationContext.

Реализации WebApplicationContext можно найти в документации:

http://static.springsource.org/spring/docs/current/api/org/springframework/web/context/WebApplicationContext.html

Не похоже, что есть класс реализации WebApplicationContext для портлета, по крайней мере, я его не нашел. Всегда можно сделать один:)

Другие вопросы по тегам