EJB 抽象方法的本地调用是否打开一个新事务?
Does local call of an EJB abstract method open a new Transaction?
假设 类 的以下构造:
一个 Filereader
找到文件的匹配导入程序并调用 Importer.import
方法。
这个方法调用了抽象方法importSpecific
,被注释为REQUIRES_NEW。
从容器的角度来看,本地调用不会开启新的事务,但从继承的角度,我不确定。
importSpecific
调用 ImporterBase.import
是否创建新交易,为什么会这样?
Class 文件读取器:
@Singleton(name = "FileReader")
public class FileReader extends Traceable {
/*@Inject
@Any
public Instance<Importer> importers;*/
@EJB
ExampleImporter importer;
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void listenToFileAvailableEvent(@Observes FileAvailable event) throws InterruptedException {
for (final String filename : event.getFilenames()) {
readFile(filename);
}
}
public void readFile(String filenameWithPath) {
//[...]-> Extract FileMetadata and find correct importer
importer.import(dateiMeta);
}
}
接口导入器:
@Local
public interface Importer {
void import(FileMetaData dateiMeta) throws Exception;
void importSpecific(FileMetaData dateiMeta) throws Exception;
}
Class 进口商基地:
public abstract class ImporterBase implements Importer {
@Resource
private SessionContext ctx;
@Override
public void import(FileMetaData dateiMeta) throws Exception {
try {
ctx.getBusinessObject(Importer.class).importSpecific(dateiMeta);//This causes the error
} catch (Exception ex) {
//[...] Log Error
throw ex;
}
}
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public abstract void importSpecific(FileMetaData dateiMeta) throws Exception;
}
Class 示例进口商:
@Stateless
public class ExampleImporter extends ImporterBase {
@Override
public void importSpecific(FileMetaData dateiMeta) throws Exception {
//Import from file
}
}
不,importSpecific
何时(以及如何)被您的方法调用 import
永远不会打开新事务;因为(如您所说)到容器的始终是本地调用...
但是,根据this,注解@TransactionAttribute
是可以继承的...所以,
为了使这种配置起作用,您必须:
1)在你的业务接口声明importSpecific
方法,即Importer
接口
2) 将 Importer
接口表示为您的本地接口。
3) 在您的 FileReader
单例中,使用 @EJB
注释获取您的 Importer Bean 的代理。如果您使用 CDI 注释(如 @Inject),容器将注入 CDI 对象而不是 EJB 代理! (注意这个)
4) 将您的 ImporterBase
代码更改为:
public abstract class ImporterBase implements Importer {
@Resource
private SessionContext ejbCtxt;
@Override
public void import(FileMetaData dateiMeta) throws Exception {
Importer proxy0;
try {
proxy0 = this.ejbCtxt.getBusinessObject(Importer.class);
proxy0.importSpecific(dateiMeta);
} catch (Exception ex) {
//[...] Log Error
throw ex;
}
}
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public abstract void importSpecific(FileMetaData dateiMeta) throws Exception;
}
5) 像这样更改您的 ExampleImporter
:
@Stateless
@Local(Importer.class)
public class ExampleImporter extends ImportBase {
...
}
如果你真的需要在你的单例中使用 CDI Bean 而不是 EJB 代理 Class,你将需要使用 @Transactional
CDI 注释来代替......你的代码也应该重构.
假设 类 的以下构造:
一个 Filereader
找到文件的匹配导入程序并调用 Importer.import
方法。
这个方法调用了抽象方法importSpecific
,被注释为REQUIRES_NEW。
从容器的角度来看,本地调用不会开启新的事务,但从继承的角度,我不确定。
importSpecific
调用 ImporterBase.import
是否创建新交易,为什么会这样?
Class 文件读取器:
@Singleton(name = "FileReader")
public class FileReader extends Traceable {
/*@Inject
@Any
public Instance<Importer> importers;*/
@EJB
ExampleImporter importer;
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void listenToFileAvailableEvent(@Observes FileAvailable event) throws InterruptedException {
for (final String filename : event.getFilenames()) {
readFile(filename);
}
}
public void readFile(String filenameWithPath) {
//[...]-> Extract FileMetadata and find correct importer
importer.import(dateiMeta);
}
}
接口导入器:
@Local
public interface Importer {
void import(FileMetaData dateiMeta) throws Exception;
void importSpecific(FileMetaData dateiMeta) throws Exception;
}
Class 进口商基地:
public abstract class ImporterBase implements Importer {
@Resource
private SessionContext ctx;
@Override
public void import(FileMetaData dateiMeta) throws Exception {
try {
ctx.getBusinessObject(Importer.class).importSpecific(dateiMeta);//This causes the error
} catch (Exception ex) {
//[...] Log Error
throw ex;
}
}
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public abstract void importSpecific(FileMetaData dateiMeta) throws Exception;
}
Class 示例进口商:
@Stateless
public class ExampleImporter extends ImporterBase {
@Override
public void importSpecific(FileMetaData dateiMeta) throws Exception {
//Import from file
}
}
不,importSpecific
何时(以及如何)被您的方法调用 import
永远不会打开新事务;因为(如您所说)到容器的始终是本地调用...
但是,根据this,注解@TransactionAttribute
是可以继承的...所以,
为了使这种配置起作用,您必须:
1)在你的业务接口声明importSpecific
方法,即Importer
接口
2) 将 Importer
接口表示为您的本地接口。
3) 在您的 FileReader
单例中,使用 @EJB
注释获取您的 Importer Bean 的代理。如果您使用 CDI 注释(如 @Inject),容器将注入 CDI 对象而不是 EJB 代理! (注意这个)
4) 将您的 ImporterBase
代码更改为:
public abstract class ImporterBase implements Importer {
@Resource
private SessionContext ejbCtxt;
@Override
public void import(FileMetaData dateiMeta) throws Exception {
Importer proxy0;
try {
proxy0 = this.ejbCtxt.getBusinessObject(Importer.class);
proxy0.importSpecific(dateiMeta);
} catch (Exception ex) {
//[...] Log Error
throw ex;
}
}
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public abstract void importSpecific(FileMetaData dateiMeta) throws Exception;
}
5) 像这样更改您的 ExampleImporter
:
@Stateless
@Local(Importer.class)
public class ExampleImporter extends ImportBase {
...
}
如果你真的需要在你的单例中使用 CDI Bean 而不是 EJB 代理 Class,你将需要使用 @Transactional
CDI 注释来代替......你的代码也应该重构.