EJB 的 SessionSynchronization#afterCompletion 方法的 CDI 等价物是什么?
What is the CDI equivalent of EJB's SessionSynchronization#afterCompletion method?
我阅读了 CDI 2.0 规范 (JSR 365) 并发现了 @Observes(during=AFTER_SUCCESS)
注释的存在,但它实际上需要定义一个自定义事件才能工作。
这是我得到的:
//simple """transactional""" file system manager using command pattern
@Transactional(value = Transactional.TxType.REQUIRED)
@TransactionScoped
@Stateful
public class TransactionalFileSystemManager implements SessionSynchronization {
private final Deque<Command> commands = new ArrayDeque<>();
public void createFile(InputStream content, Path path, String name) throws IOException {
CreateFile command = CreateFile.execute(content, path, name);
commands.addLast(command);
}
public void deleteFile(Path path) throws IOException {
DeleteFile command = DeleteFile.execute(path);
commands.addLast(command);
}
private void commit() throws IOException{
for(Command c : commands){
c.confirm();
}
}
private void rollback() throws IOException{
Iterator<Command> it = commands.descendingIterator();
while (it.hasNext()) {
Command c = it.next();
c.undo();
}
}
@Override
public void afterBegin() throws EJBException{
}
@Override
public void beforeCompletion() throws EJBException{
}
@Override
public void afterCompletion(boolean commitSucceeded) throws EJBException{
if(commitSucceeded){
try {
commit();
} catch (IOException e) {
throw new EJBException(e);
}
}
else {
try {
rollback();
} catch (IOException e) {
throw new EJBException(e);
}
}
}
}
但是,我想采用仅 CDI 的解决方案,因此我需要删除所有与 EJB 相关的内容(包括 SessionSynchronization
接口)。我怎样才能使用 CDI 获得相同的结果?
首先是事实:本主题的权威来源是 Java 事务 API (JTA) 规范。网上一搜,得到了this.
然后是坏消息:为了真正参与 JTA 事务,您要么必须根据 Java 连接器体系结构 (JCA) 规范实施连接器,要么根据 XAResource
JTA。从来没有做过,恐怕两者都会很难。不过,如果您进行搜索,您可能会找到文件系统连接器的现有实现。
您上面的代码永远不会完成真正的两阶段提交,因为如果您的代码失败,事务已经提交,因此应用程序状态不一致。或者,有一小段时间 window 当实际事务提交但文件系统更改尚未执行时,状态再次不一致。
一些解决方法我能想到,none其中解决了一致性问题:
- 将文件系统命令保存在数据库中。这确保它们以事务方式排队。计划的作业唤醒并实际尝试执行排队的 FS 命令。
- 注册一个
Synchronization
with the current Transaction
,从那里触发一个适当的事件。您的 TransactionalFileSystemManager
观察到此事件,我猜不需要 during
属性。
我阅读了 CDI 2.0 规范 (JSR 365) 并发现了 @Observes(during=AFTER_SUCCESS)
注释的存在,但它实际上需要定义一个自定义事件才能工作。
这是我得到的:
//simple """transactional""" file system manager using command pattern
@Transactional(value = Transactional.TxType.REQUIRED)
@TransactionScoped
@Stateful
public class TransactionalFileSystemManager implements SessionSynchronization {
private final Deque<Command> commands = new ArrayDeque<>();
public void createFile(InputStream content, Path path, String name) throws IOException {
CreateFile command = CreateFile.execute(content, path, name);
commands.addLast(command);
}
public void deleteFile(Path path) throws IOException {
DeleteFile command = DeleteFile.execute(path);
commands.addLast(command);
}
private void commit() throws IOException{
for(Command c : commands){
c.confirm();
}
}
private void rollback() throws IOException{
Iterator<Command> it = commands.descendingIterator();
while (it.hasNext()) {
Command c = it.next();
c.undo();
}
}
@Override
public void afterBegin() throws EJBException{
}
@Override
public void beforeCompletion() throws EJBException{
}
@Override
public void afterCompletion(boolean commitSucceeded) throws EJBException{
if(commitSucceeded){
try {
commit();
} catch (IOException e) {
throw new EJBException(e);
}
}
else {
try {
rollback();
} catch (IOException e) {
throw new EJBException(e);
}
}
}
}
但是,我想采用仅 CDI 的解决方案,因此我需要删除所有与 EJB 相关的内容(包括 SessionSynchronization
接口)。我怎样才能使用 CDI 获得相同的结果?
首先是事实:本主题的权威来源是 Java 事务 API (JTA) 规范。网上一搜,得到了this.
然后是坏消息:为了真正参与 JTA 事务,您要么必须根据 Java 连接器体系结构 (JCA) 规范实施连接器,要么根据 XAResource
JTA。从来没有做过,恐怕两者都会很难。不过,如果您进行搜索,您可能会找到文件系统连接器的现有实现。
您上面的代码永远不会完成真正的两阶段提交,因为如果您的代码失败,事务已经提交,因此应用程序状态不一致。或者,有一小段时间 window 当实际事务提交但文件系统更改尚未执行时,状态再次不一致。
一些解决方法我能想到,none其中解决了一致性问题:
- 将文件系统命令保存在数据库中。这确保它们以事务方式排队。计划的作业唤醒并实际尝试执行排队的 FS 命令。
- 注册一个
Synchronization
with the currentTransaction
,从那里触发一个适当的事件。您的TransactionalFileSystemManager
观察到此事件,我猜不需要during
属性。