Избавьтесь от *-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 можно найти в документации:
Не похоже, что есть класс реализации WebApplicationContext для портлета, по крайней мере, я его не нашел. Всегда можно сделать один:)