Бин @Singleton не удалось инициализировать из-за непредвиденного состояния транзакции
У меня был сценарий, в котором мне нужно было загрузить один компонент (ReportManager) при запуске приложения, чтобы он мог планировать отчеты для выполнения (опрашиваемый из базы данных компонентом DataStore).
Погуглив, я нашел аннотации @Singleton, @Startup и @DependsOn, которые я использовал так:
@Singleton
@Startup
@DependsOn("DataStore")
public class ReportManager {
@EJB
DataStore dataStore;
@PostConstruct
public void scheduleReports() {
logger.log("INITIALIZED");
List<Report> reports = dataStore.getReports();
....
}
}
@Singleton
@RolesAllowed("user") //I had security checks implemented like that beforehand
public class DataStore {
@PostConstruct
public void initialize() {
logger.log("INITIALIZED");
}
public List<Report> getReports() {
...
}
}
Проблема заключалась в том, что во время развертывания я получал действительно странное исключение:
<2012-09-27 14:04:15 CEST> <Warning> <Deployer> <BEA-149004> <Failures were detected while initiating deploy task for application "app".>
<2012-09-27 14:04:15 CEST> <Warning> <Deployer> <BEA-149078> <Stack trace for message 149004
weblogic.application.ModuleException: Exception starting module: EJBModule(app-ejb-1.0-SNAPSHOT.jar)
Unable to deploy EJB: ReportManager from app-ejb-1.0-SNAPSHOT.jar:
Singleton ReportManager(Application: app, EJBComponent: app-ejb-1.0-SNAPSHOT.jar) failed to initialize.
at weblogic.ejb.container.deployer.EJBModule.start(EJBModule.java:592)
.....
Caused By: weblogic.ejb.container.InternalException: Transaction marked rollback or not expected transaction status: 1
at weblogic.ejb.container.manager.SingletonSessionManager.postCallback(SingletonSessionManager.java:464)
Не очень страшное сообщение об исключении. Тем более, что я также не получал никаких "ИНИЦИАЛИЗИРОВАННЫХ" записей журнала. Когда я закомментировал вызов dataStore.getReports (), все работало нормально, и бины были сконструированы в правильном порядке (были созданы сообщения "INITIALIZED"). Включение вызова метода dataStore вызывало вышеуказанную ошибку и каким-то образом подавляло весь вывод журнала.
Я использую Weblogic 12c.
2 ответа
Наконец я понял, что является причиной ошибки. Это было @RolesAllowed
объявление, которое блокировало вызов метода из-за пустого контекста безопасности, не задано в @PostConstruct
метод при выполнении в @Startup
bean (из спецификации EJB 3.1, гл. 4.3.4: методы перехватчика обратного вызова жизненного цикла PostConstruct выполняются в неопределенном контексте безопасности.).
Для того, чтобы это работало, нужно было просто добавить @PermitAll
к вызываемому методу:
@PermitAll
public List<Report> getReports() {
...
}
Ошибка была настолько обманчива, что я решил поместить это дело здесь, так как не смог найти ответ в Google.
В моем случае я использую класс SpringLoader.java, который является @Singleton, который загружает конфигурацию Spring. Spring настроен с планировщиком Quartz, который пытается получить доступ к своим таблицам БД (как часть какой-либо транзакции).
Так что в моем случае это помогло добавить следующую строку в этот класс SpringLoader: @TransactionManagement(TransactionManagementType.BEAN)
После этого отображается еще одно значимое сообщение об ошибке: ORA-00942: таблица или представление не существует.
Кстати, это также стоило добавить эту строку: @ConcurrencyManagement(ConcurrencyManagementType.BEAN)