Бину @Singleton не удалось инициализироваться из-за непредвиденного состояния транзакции 4, когда он помечен как TransactionAttribute=NOT_SUPPORTED
У меня возникли проблемы с инициализацией EJB3.1-компонента и, в частности, из-за сбоя в его работе из-за предполагаемого отката транзакции, даже если я пометил EJB-компонент как @TransactionAttribute(NOT_SUPPORTED)
, Это должно означать, что любая клиентская транзакция приостанавливается на входе в метод bean до выхода (когда она будет возобновлена. Это определенно транзакционная проверка, которую я хочу.
"Суть" кода и ошибки заключаются в следующем (обратите внимание, что некоторые из них ручные, чтобы скрыть детали, но все они актуальны и репрезентативны):
@Singleton(name = "MyClass")
@ConcurrencyManagement(value = BEAN)
@TransactionAttribute(value = NOT_SUPPORTED)
@Local(MyInterface.class)
public class MyClass implements MyInterface {
@PostConstruct
public void init() throws MyException {
try {
...
} catch LowerLevelException e) {
throw new MyException("problem", e);
}
}
public Object doSomething(...) throws MyException {
...
}
...
}
Это вызывает следующую ошибку:
javax.ejb.NoSuchEJBException: Singleton MyClass(Application: my-ear, EJBComponent: my-ejb.jar) failed to initialize.
который, когда я отлаживаю, на самом деле упаковывает следующее исключение:
weblogic.ejb.container.InternalException: Transaction marked rollback or not expected transaction status: 4
Опять же, отладка поднимает некоторые интересные детали:
- Во-первых, мой
MyClass#init
выполняется полностью и успешно без каких-либо проблем / исключений. -
#init
вызывается по первому звонку на мой#doSomething
метод из клиентского кода (как часть пост-конструкции). - Таким образом, существует множество уровней косвенности стека между вызовом клиента к
MyClass#doSomething
до#init
и исключение поднимается внутри одного из этих слоев. Это поднято в коде управления сессионным компонентом WLS. Увидеть ниже...
Стек похож на приведенный ниже (имена MyClass изменены):
MyClass_fefgu8_Impl(MyClass).init() line: 96
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 57
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43
Method.invoke(Object, Object...) line: 601
Jsr250Metadata.invokeLifecycleMethod(Object, Method, Object[]) line: 393
InterceptionMetadata(Jsr250Metadata).invokeLifecycleMethods(Object, LifecycleEvent) line: 365
InterceptionMetadata.invokeLifecycleMethods(Object, LifecycleEvent) line: 403
EjbComponentCreatorImpl.invokePostConstruct(Object, String) line: 80
SingletonSessionManager.constructAndInitBean() line: 369
SingletonSessionManager.access$300(SingletonSessionManager) line: 63
SingletonSessionManager$SingletonLifecycleManager.doActualInit() line: 798 <== InternalException raised here
SingletonSessionManager$SingletonLifecycleManager.initInternal(boolean) line: 744
SingletonSessionManager$SingletonLifecycleManager.getBean() line: 648
SingletonSessionManager.getBeanFor(InvocationWrapper) line: 285
SingletonSessionManager.preInvoke(InvocationWrapper) line: 147
SingletonLocalObject(BaseLocalObject).getBeanInstance(InvocationWrapper) line: 146
SingletonLocalObject(BaseLocalObject).preInvoke(InvocationWrapper, ContextHandler, boolean, boolean) line: 103
SingletonLocalObject(BaseLocalObject).__WL_preInvoke(InvocationWrapper, ContextHandler) line: 67
SessionLocalMethodInvoker.invoke(Invokable, BaseLocalObject, InvocationWrapper, Object[], int) line: 20
MyClass_fefgu8_MyInterfaceImpl.doSomething(String, String, String, String) line: not available
И исключение отката транзакции фактически возникает в стеке:
SingletonSessionManager$SingletonLifecycleManager.doActualInit() line: 798
Этот уровень имеет дело с менеджером транзакций, но я понятия не имею, почему он должен пытаться пометить транзакцию для отката, особенно после успешной инициализации из основного кода приложения.
Я использую этот EJB-компонент для компиляции этого компонента, но мы используем код WLS EJB на сервере (или курс):
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.ejb</artifactId>
<version>3.1</version>
<scope>provided</scope>
</dependency>
Причина, по которой я это изложил, заключается в том, что это оказалось непросто, в сети очень мало ценного (особенно с состоянием транзакции 4), я потратил немного времени на это и должен двигаться дальше. Я продолжаю смотреть, но я думал, что смогу получить больше потенциальных клиентов, когда вернусь в понедельник.
Я перечитал много об обработке транзакций EJB и не вижу никаких очевидных проблем. Я считаю, что я использую правильный механизм для обработки транзакции в моем bean-компоненте (т.е. он не транзакционный). Я еще не пытался поместить это в дескриптор вместо этого (о котором я только что подумал и попробую). Я также еще не углубился в то, как SingletonSessionManager$SingletonLifecycleManager.doActualInit
работает, но там не так много онлайн об этом.
Вопрос
Перефразируя, вопрос в следующем: - Чего мне не хватает, чтобы мои методы bean-компонентов не участвовали ни в одной из предоставленных транзакций или, более конкретно, не пытались пометить транзакцию для отката? - Почему он не может инициализироваться с этой ошибкой, если я прямо сказал ей не "поддерживать" (заботиться о) какие-либо транзакции?
NB. Я проверил, что этот бин @Singleton не удалось инициализировать из-за непредвиденной проблемы статуса транзакции 1, но мой сценарий не связан с разрешениями роли безопасности Java EE (я не думаю!)
Благодарю.
Обновление 1
Ну, последнее, что удаление моего @TransactionAttribute
аннотация, кажется, помогает мне преодолеть неудачу. Это странно, так как по умолчанию должно быть TransactionAttributeType#Required, и действительно, у нас есть дополнительный слой в трассировке стека, и если я отлаживаю слишком долго, я получаю тайм-аут транзакции в моем bean init.
Глядя на следующий уровень в трассировке стека (медленно вытесняя), я вижу, что есть транзакция (ну, на самом деле, два):
SingletonSessionManager.constructAndInitBean() line: 377
wrap weblogic.ejb.container.internal.InvocationWrapper (id=15676)
L callerTx weblogic.transaction.internal.ServerTransactionImpl (id=15681)
L invokeTx weblogic.transaction.internal.ServerTransactionImpl (id=15683)
Я проверю, присутствовали ли они в предварительном удалении @TransactionAttribute
сценарий, а также попробовать и посмотреть ServerTransactionImpl
,
Обновление 2
Последнее обновление на некоторое время... Тем не менее, я думаю, что я проследил проблему в SingletonSessionManager#postCallback
который вызывается из SingletonSessionManager#constructAndInitBean
в оригинальной трассировке стека выше. (Я должен был подтвердить это, хотя, поскольку мое лидерство определено, пробегая транзакционный случай). Будет сообщать, если / когда, но кажется, что у нас может быть ошибка при попытке откатить нашу несуществующую транзакцию здесь.
1 ответ
NB. Первоначально это был не ответ, а просто полезная информация, в которой можно найти ответы на такие проблемы, поскольку в этой области на самом деле не так много информации. После некоторых дополнительных усилий причина и ответ были найдены. Ответ был оставлен в его оригинальном формате с новыми результатами, задокументированными как исправления, и помощь в отладке, оставленная без изменений, чтобы, надеюсь, облегчить отладку других с похожими проблемами. Это темное место.
Что ж, до сих пор нет твердого ответа на вышеуказанный вопрос, и проблема, похоже, ушла.
Я нашел, хотя (глядя на другой NoSuchEJBException
проблема), что основная причина проглатывается стеком WLS.
Это разумное место для начала поиска SingletonBean, который не смог инициировать проблемы NosuchEJBException в тех случаях, когда вы не включили его в свой PostConstruct
Метод (т.е. ваш бин не может быть создан):
SingletonSessionManager$SingletonLifecycleManager.doActualInit() line: 819
SingletonSessionManager$SingletonLifecycleManager.initInternal(boolean) line: 744
SingletonSessionManager$SingletonLifecycleManager.getBean() line: 648
SingletonSessionManager.getBeanFor(InvocationWrapper) line: 285
Первоначально корневые исключения обнаруживаются и включаются в NoSuchEJBException
подняты на нижних уровнях, как указано выше. Тем не менее, в точке в стеке ниже, NoSuchEJBException
заменяется на InternalError
это обернуто и причина (ы) потеряна. Любопытно, что он может даже установить себя как причину (отладчик работает немного неэффективно):
SingletonSessionManager#getBeanFor
Таким образом, это отличное место для нахождения корневого исключения.
К сведению: моя проблема во втором случае заключалась в проблеме подпружиненного внедрения в WLS (перепакованная пружина), когда источник данных не был должным образом введен в мою службу ELB, так как источник данных не существовал с @Resource(name="...")
Имя JNDI. Это не было зарегистрировано вообще из-за вышеупомянутой проблемы обработки исключений. Как только я вошел и нашел причину, это было легко исправить. Стыдно тратить столько времени на то, чтобы это выяснить.
[РЕДАКТИРОВАТЬ] К вашему сведению: Кажется, моя проблема, вызвавшая исключение "Внутренний статус транзакции откат 4", могла быть вызвана тем, что EJB init (PostConstruct) превысил время ожидания транзакции. Это не имеет значения, если мой EJB установлен как @TransactionAttribute(NOT-SUPPORTED)
но, видимо, не так. Отладка показала, что для этого и @TransactionAttribute(NEVER)
, есть invokeTx
используется на уровне SingletonSessionManager#constructAndInitBean
и удалось в InvocationWrapper
, Таким образом, тайм-аут вызовет откат, что приведет к InternalException
, сопоставленный с NoSuchEJBException
проглоченный другим NoSuchEJBException
приводя к сообщению об ошибке мусора.
[EDIT2] К вашему сведению: это происходит из-за ошибки в WLS, когда invokeTx установлен и управляется, когда это не должно быть @TransactionAttribute(NOT-SUPPORTED)
, Мы подняли ошибку в Oracle, который дал ему 2 балла. Тем временем мы удалили потенциально трудоемкий (зависящий от сети) код из @PostConstruct
метод в качестве обходного пути.
[EDIT3] К вашему сведению: Из Oracle ... Аннотация атрибута транзакции уровня класса не применяется на одноэлементных перехватчиках жизненного цикла postconstrcut/predestroy, поэтому по умолчанию используется значение REQUIRED.
Они согласны с тем, что это проблема, и изучают ее. В то же время убедитесь, что тайм-ауты транзакций не нарушаются кодом в вашей @PostConstruct
, Это будет включать тайм-ауты на основе задержек (наша проблема была прерывистой, поскольку она зависела от того, к какому географическому "серверу" обращались).
Советы по отладке
Кстати, в процессе отладки, я полагаю, я бы:
- Поставьте точку останова в вашем EJB init (
@PostConstruct
) и раскручивайте до тех пор, пока вы не увидите исключение в ваших значениях отладки. - Если вы не нажали кнопку инициализации, установите точки останова как можно ближе к WLS.
#doActualInit
перечисленные выше и найдите свой путь в методы init. затем просто посмотрите, когда возникнет исключение. Обратите внимание, что вам, возможно, придется поместить свою точку останова внутрьInvocationHandler#invoke
чтобы приблизиться к этому через прокси-слои (или сверните свои собственные). - Если вы нажмете на него, посмотрите на стек раскручивания, поставив точку останова в
init
и разматывать или вEjbComponentCreatorImpl.invokePostConstruct(Object, String)
и смотреть.