Бин @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)

Другие вопросы по тегам