我需要在完成用户上传的长时间处理后回复一个事件。我需要将返回值设置为用户会话,以便我可以正确地解决它。我正在做一些CDI魔术,如下所述:http://piotrnowicki.com/2013/05/asynchronous-cdi-events/#toc-solution-3-ejb-producer-and-cdi-consumer(Async EJB Producer - > CDI Consumer)。
首次尝试
来电者& Reciver:
@SessionScoped
public class UploadController implements Serializable {
private static final long serialVersionUID = 1L;
private final Logger logger = Logger.getLogger(this.getClass());
@EJB
private StatelessBeanLocal statelessBean;
@Inject
private SomeSessionCdi cdi;
private Future<UploadedDTO> futureDto;
public void observeUpload(@Observes(during = TransactionPhase.AFTER_COMPLETION) UploadFinishedEvent event) {
logger.trace("Recived CDI event: %s", event);
// FIXME: without @SessionScoped i'm reaching here, but futureDto == null
cdi.setStateAfterUpload(dto);
}
public void upload(ByteArrayOutputStream baos, User user, UploadedFileInfo info) {
logger.trace("Initiating an async upload processing of %s", info);
futureDto = statelessBean.upload(baos, user);
logger.trace("Initialized an async upload processing of %s", info);
}
}
处理器:
@Stateless
public class StatelessBean implements StatelessBeanLocal {
@Inject
private transient Event<UploadFinishedEvent> eventTrigger;
@Asynchronous
public Future<UploadedDTO> upload(ByteArrayOutputStream baos, User user) {
UploadedEntity entity = Unpacker.unpackBaos(baos);
logger.trace("Uploaded file for: %s", entity);
// [..] Long processing here
// Invoking Thread.sleep(5000); to simulate a long process
Thread.sleep(5000);
UploadedDTO dto = null; // here a real value, of course
logger.debug("Finished processing of upload for: %s", entity);
eventTrigger.fire(new UploadFinishedEventImpl());
logger.trace("After firing a CDI event for finished upload for: %s", entity);
return new AsyncResult<>(dto);
}
// [..]
}
如果CDI bean有@SessionScoped
注释,那么我得到:SEVERE: WELD-000401 Failure while notifying an observer of event org.example.StatelessBean$UploadFinishedEventImpl@54c03555
如果CDI bean没有@SessionScoped
注释,那么我得到futureDto == null
第二次尝试
将EJB bean更改为更改日志但仍不起作用:
更改无状态EJB:
@Stateless
public class StatelessBean implements StatelessBeanLocal {
@Inject
private transient Event<UploadFinishedEvent> eventTrigger;
@Resource
private SessionContext sctx;
@Asynchronous
public Future<UploadedDTO> upload(ByteArrayOutputStream baos, User user) {
UploadedEntity entity = Unpacker.unpackBaos(baos);
logger.trace("Uploaded file for: %s", entity);
// [..] Long processing here
// Invoking Thread.sleep(5000); to simulate a long process
Thread.sleep(5000);
UploadedDTO dto = null; // here a real value, of course
logger.debug("Finished processing of upload for: %s", entity);
sctx.getBusinessObject(TemplateSetBeanLocal.class).fireUploadFinished();
logger.trace("After firing a CDI event for finished upload for: %s", entity);
return new AsyncResult<>(dto);
}
@Asynchronous
public void fireUploadFinished() {
logger.debug("Before firing an UploadFinishedEvent: %s", sctx.getCallerPrincipal().toString());
eventTrigger.fire(new UploadFinishedEventImpl());
logger.debug("After firing an UploadFinishedEvent: %s", sctx.getCallerPrincipal().toString());
}
// [..]
}
日志:
FINE: Finished processing of upload for: [sample-0.1.0-SNAPSHOT.zip,application/zip,75,80KB,3cgvet] FINEST: After firing a CDI event for finished upload for: [sample-0.1.0-SNAPSHOT.zip,application/zip,75,80KB,3cgvet] FINE: Before firing an UploadFinishedEvent: admin FINE: After firing an UploadFinishedEvent: admin SEVERE: No valid EE environment for injection of org.example.UploadController FINEST: Recived CDI event: org.example.StatelessBean$UploadFinishedEventImpl@72514572
有可能吗?
答案 0 :(得分:1)
是的,有可能。 如果没有@SessionScoped,则会再次创建bean,因此futureDTO为null。 使用@SessionScoped @AfterCompletion,您将在事务提交后进行处理。您获得的焊接错误可能是由于某些交易行为造成的。虽然不在示例中,但您可能正在调用另一个EJB方法来处理observeUpload()中的uploadDTO,从而导致已提交事务(@AfterCompletion)被暂停和恢复,这是不可能的。解决方案是使用有效的事务输入观察者方法,或者不在该方法中进行任何事务处理。有时,具有适当事务上下文的额外层/方法将有所帮助。
答案 1 :(得分:0)
Mayby尝试这样的事情:
@SessionScoped
public class UploadController implements Serializable {
private static final long serialVersionUID = 1L;
private final Logger logger = Logger.getLogger(this.getClass());
@EJB
private StatelessBeanLocal statelessBean;
private Future<UploadedDTO> futureDto;
public void uploadEnded(UploadedDTO dto) {
logger.trace("Uploaded " + dto);
}
public void upload(ByteArrayOutputStream baos, User user, UploadedFileInfo info) {
logger.trace("Initiating an async upload processing of %s", info);
futureDto = statelessBean.upload(baos, user, this);
logger.trace("Initialized an async upload processing of %s", info);
}
}
EJB:
@Stateless
public class StatelessBean implements StatelessBeanLocal {
@Asynchronous
public Future<UploadedDTO> upload(ByteArrayOutputStream baos, User user, UploadController controller) {
UploadedEntity entity = Unpacker.unpackBaos(baos);
logger.trace("Uploaded file for: %s", entity);
// [..] Long processing here
// Invoking Thread.sleep(5000); to simulate a long process
Thread.sleep(5000);
UploadedDTO dto = null; // here a real value, of course
logger.debug("Finished processing of upload for: %s", entity);
controller.uploadEnded(dto);
logger.trace("After firing a CDI event for finished upload for: %s", entity);
return new AsyncResult(dto);
}
// [..]
}