2012-07-10 257 views
2

我試過在我的Spring(v 3.1)Web應用程序中使用scala編程的一些bean,並且在交易時遇到了奇怪的問題。Scala的春季交易

我已經在Roo中設置了一個小而完整的Spring應用程序來顯示我的問題。說實話,我沒有一個線索,爲什麼它不工作做...

project --topLevelPackage com.app 
jpa setup --provider ECLIPSELINK --database DERBY_EMBEDDED 
entity jpa --class com.app.MyEntity 
field string --fieldName title 

然後,我創建的接口在Java中

package com.app; 
public interface IScalaMainClass { 
void doSomething(); 
} 

package com.app; 
public interface IScala1 { 
void someMethod(); 
} 

package com.app; 
public interface IScala2 { 
void someMethod(); 
} 

這些實現在Scala中創建其中Scala1持續myEntity所和Scala2使得DELETE查詢:

package com.app 

import org.springframework.transaction.annotation.Transactional 
import org.springframework.stereotype.Repository 
import org.springframework.beans.factory.annotation.Autowired 

@Repository class ScalaMainClass extends com.app.IScalaMainClass { 
@Autowired var bean1: IScala1 = null 
@Autowired var bean2: IScala2 = null 

@Transactional def doSomething() = { 
    bean1.someMethod() 
    bean2.someMethod() 
} 
} 


package com.app 

import org.springframework.stereotype.Repository 
import javax.persistence.{EntityManager, PersistenceContext} 

@Repository class Scala1 extends com.app.IScala1 { 
@PersistenceContext var em: EntityManager = null 

def someMethod = { 
    val e = new MyEntity 
    em persist e 
} 
} 


package com.app 

import org.springframework.transaction.annotation.Transactional 
import org.springframework.stereotype.Repository 
import javax.persistence.{EntityManager, PersistenceContext} 

@Repository class Scala2 extends com.app.IScala2 { 
@PersistenceContext var em: EntityManager = null 

@Transactional def someMethod = { 
    val q = em createQuery "DELETE FROM MyEntity" 
    q executeUpdate 
} 

}

最後在Java中,測試是CR eated它執行IScalaMainClass:

import org.springframework.test.context.ContextConfiguration; 
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 
import org.springframework.test.context.transaction.TransactionConfiguration; 
import org.springframework.test.annotation.Rollback; 
import org.springframework.beans.factory.annotation.Autowired; 

import org.junit.runner.RunWith; 
import org.junit.Test; 
import org.junit.Assert; 

import com.app.IScalaMainClass; 

@ContextConfiguration(locations = "classpath:/META-INF/spring/applicationContext.xml") 
@RunWith(SpringJUnit4ClassRunner.class) 
@TransactionConfiguration(defaultRollback = false) 
public class AppTest { 
@Autowired private IScalaMainClass smc; 

@Test public void testIt() { 
    smc.doSomething(); 
} 
} 

如果你現在添加斯卡拉依賴關係的pom.xml,做「MVN測試」,您將收到

javax.persistence.TransactionRequiredException: 
Exception Description: No transaction is currently active 
... 
+3

你需要表現出更多的代碼,你怎麼稱呼'DoSomething的()' ,它是一些特性的一部分('IScalaMainClass'),你如何配置@Transactional(XML?),你能顯示*沒有正在進行的事務*異常的線程轉儲嗎?如何構建應用程序(在啓動期間未能找到類)。我可以向你保證,斯卡拉與Spring完美合作。 – 2012-07-10 12:06:04

+0

我現在已經用完整的示例擴展了我的原始內容,以便您可以逐步重建問題 – rainerhahnekamp 2012-07-12 10:24:19

回答

2

你必須要非常小心,當你看看Spring支持Transaction和其他面向方面的功能。

  • 自動裝配一個不可變的領域是不可能的:自動裝配是初始化後建立依賴的模式,VAL是一個不可改變的屬性,它不能初始化

  • 後更改正如你可以在文檔中讀取, Spring AOP的支持不是基於字節碼編織,它是純Java實現的:http://static.springsource.org/spring/docs/3.0.x/reference/aop.html

這意味着,只有它們通過Spring IoC來創建豆可能受益的Spring AOP的支持。

如果您在介紹該章的看,你可以讀到:

AOP在Spring框架中使用...

提供聲明式企業服務,特別是作爲一個 替換EJB聲明式服務。最重要的這種服務是聲明式事務管理。

所以如果你的bean不是通過Spring創建的,你將不會有彈簧事務支持。

+0

您是對的。我在Java中創建了一個用@Transactional註釋的ScalaMainClassFacade,並簡單地調用自動裝配的ScalaMainClass。但是沒有任何方法可以單獨使用Scala嗎? – rainerhahnekamp 2012-07-15 15:21:00

+0

不符合Spring AOP設計的方式。這個文檔解釋了它(但我同意可以進一步加下劃線):Spring AOP不能這樣做,因爲它不執行字節碼注入,並且沒有針對方面的特殊編譯過程:在運行時,當IoC容器加載上下文,它有一些BeanFactoryPostProcessors負責應用你的方面。所以,沒有IoC,沒有方面。如果您希望在IOC之外提供面向AOP的編程,您必須使用AspectJ而不是Spring AOP – Edmondo1984 2012-07-15 19:00:42

+0

我實際上想補充一點,開發您自己的事務管理方面將在Spring之外使用並不是微不足道的。事務註釋做的是告訴Spring使用應用上下文中可用的平臺事務管理器來啓動和提交或回滾事務。如果你想要在容器外運行的代碼,你會在哪裏獲得對事務管理器的引用? – Edmondo1984 2012-07-16 06:06:05

1

雖然我主要贊同@ Edmondo1984的回答,但我認爲rainerh的代碼已經將所有bean放在Spring上下文中,因此它可以與Spring Transaction一起使用。

從上面的代碼,我想你應該改變測試如下

@ContextConfiguration(locations = "classpath:/META-INF/spring/applicationContext.xml") 
public class AppTest extends AbstractTransactionalJUnit4SpringContextTests { 
@Autowired private IScalaMainClass smc; 

@Test public void testIt() { 
    smc.doSomething(); 
} 
} 

不要忘了導入org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests