如何在没有服务构建器的情况下在liferay事务中创建服务方法

时间:2013-03-01 18:58:04

标签: hibernate liferay liferay-6 spring-transactions transactional

我有一个名为NotificationService的实用程序服务。它遵循MailService的路线,即服务层具有NotificationService接口(定义服务)和NotificationServiceUtil类(静态提供服务),并且我有一个提供NotificationServiceImpl(实现)的impl层。然后我在ext-spring.xml中注册了该服务:

  <bean id="org.mitre.asias.portal.notification.service.NotificationService"
    class="org.mitre.asias.portal.notification.service.impl.NotificationServiceImpl">
    ...
  </bean>
  <bean id="org.mitre.asias.portal.notification.service.NotificationServiceUtil"
    class="org.mitre.asias.portal.notification.service.NotificationServiceUtil">
    <property name="service"
      ref="org.mitre.asias.portal.notification.service.NotificationService" />
  </bean>

一切都按预期工作,直到我尝试将交易投入到混合中。我在NotificationServiceImpl中有一个需要是事务性的方法:

public void sendAndUpdate( Message message, List<Event> eventsToUpdate ) throws SystemException, MessagingException {
    for ( Event event : eventsToUpdate ) {
        eventLocalService.updateEvent( event );
    }
    Transport.send( message );
}

这个想法是,如果由于某种原因发送消息失败,模型对象的更改将被回滚,以便我可以稍后重试发送。我尝试用以下方法注释这个方法:

@Transactional( isolation = Isolation.PORTAL,
        rollbackFor = { PortalException.class, SystemException.class, MessagingException.class } )

但它没有采取。我尝试将该注释移动到NotificationService接口,但仍然没有骰子。我在org.hibernate.transaction.JDBCTransaction上启用了调试日志记录,并且可以看到对该方法的调用从未启动事务,但是为循环中的每个updateEvent调用启动并提交了一个事务。

进入源代码,看来Liferay有一个名为ServiceBeanAutoProxyCreator的bean后处理器,它有以下代码:

...
protected Object[] getAdvicesAndAdvisorsForBean(
        Class<?> beanClass, String beanName, TargetSource targetSource)
    throws BeansException {

    if (beanName.endsWith(_SERVICE_SUFFIX)) {
        return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS;
    }
    else {
        return DO_NOT_PROXY;
    }
}

private static final String _SERVICE_SUFFIX = "Service";
...

这使得看起来每个名称以Service结尾的bean(如我的bean所做的那样:...id="org.mitre.asias.portal.notification.service.NotificationService"...)应该包含在ServiceBeanAopProxy中,这将根据生成的服务构建器添加事务建议base-spring.xml

<bean class="com.liferay.portal.spring.aop.ServiceBeanAutoProxyCreator">
    <property name="methodInterceptor" ref="serviceAdvice" />
</bean>
<bean class="com.liferay.portal.spring.context.PortletBeanFactoryCleaner" />
<bean class="com.liferay.portal.spring.context.PortletBeanFactoryPostProcessor" />
<bean class="com.liferay.portal.spring.bean.BeanReferenceAnnotationBeanPostProcessor" />
<bean id="portletClassLoader" class="com.liferay.portal.kernel.portlet.PortletClassLoaderUtil" factory-method="getClassLoader" />
<bean id="servletContextName" class="com.liferay.portal.kernel.portlet.PortletClassLoaderUtil" factory-method="getServletContextName" />
<bean id="basePersistence" abstract="true">
    <property name="dataSource" ref="liferayDataSource" />
    <property name="sessionFactory" ref="liferaySessionFactory" />
</bean>
<bean id="serviceAdvice" class="com.liferay.portal.monitoring.statistics.service.ServiceMonitorAdvice">
    <property name="monitoringDestinationName" value="liferay/monitoring" />
    <property name="nextMethodInterceptor" ref="asyncAdvice" />
</bean>
<bean id="asyncAdvice" class="com.liferay.portal.messaging.async.AsyncAdvice">
    <property name="defaultDestinationName" value="liferay/async_service" />
    <property name="nextMethodInterceptor" ref="threadLocalCacheAdvice" />
</bean>
<bean id="threadLocalCacheAdvice" class="com.liferay.portal.cache.ThreadLocalCacheAdvice">
    <property name="nextMethodInterceptor" ref="transactionAdvice" />
</bean>
<bean id="transactionAdvice" class="com.liferay.portal.spring.transaction.TransactionInterceptor">
    <property name="transactionAttributeSource" ref="transactionAttributeSource" />
    <property name="transactionManager" ref="liferayTransactionManager" />
</bean>
<bean id="transactionAttributeSource" class="com.liferay.portal.spring.transaction.AnnotationTransactionAttributeSource" />

有没有人知道如何才能使这项工作?

我在tomcat 6.0.32容器中使用Liferay 6.0 EE sp2。

1 个答案:

答案 0 :(得分:0)

尝试将@transactional注释移到界面上(而不是界面方法)

Liferay将事务包装在名称以Service结尾的bean上(取决于bean名称而不是类名)。

问题还在于放置代码。你在哪里定义你的bean?我想在extplugin?如果您希望在没有服务构建器的情况下在自己的portlet中扩展Liferay事务,那么它可能会变得棘手。但是应该可以在6.1中分享Liferay spring上下文。