Spring DefaultAdvisorAutoProxyCreator с @Transactional вызывает проблемы

Я работаю над проектом Spring MVC и пытаюсь интегрировать Apache Shiro для обеспечения безопасности. Все шло как по маслу, пока я не понял, что Hibernate преждевременно закрывает сеанс/соединение после одного запроса и вызывает исключение lazyinit. Неудивительно, что то, что я делал, должно быть сделано внутри транзакции, чтобы сеанс не был закрыт.

Дилеммы…

  1. Я попытался поместить @Transactional в свой метод контроллера, но тогда я получаю 404. Глядя на свои журналы, я вижу, что при начальной загрузке Spring игнорирует любые сопоставления в моем HomeController, если эта аннотация @Transactional находится в любом методе внутри контроллера.

  2. Без @Transactional он загружается просто отлично, и я вижу, что bean-компонент RequestMappingHandlerMapping видит все аннотации @RequestMapping в моем контроллере.

  3. С @Transactional, но без DefaultAdvisorAutoProxyCreator, и это работает, за исключением того, что аннотации Широ просто игнорируются.

tldr: Широ требует DefaultAdvisorAutoProxyCreator, но если я создам этот компонент, Spring перестанет работать при использовании аннотации @Transactional.

Я прошу о помощи, потому что я совершенно не понимаю, как действовать в этот момент.


person Danny.Parker2002    schedule 10.08.2012    source источник


Ответы (1)


Обычно это происходит потому, что когда вы помещаете @Transactional в метод, Spring создает динамический прокси для этого компонента — если компонент реализует интерфейс, то динамический прокси создается на основе этого интерфейса, в противном случае для создания прокси будет использоваться CGLIB.

Я предполагаю, что проблема в вашем случае заключается в том, что вы, вероятно, основываете свой контроллер на каком-то интерфейсе или расширяете его на основе базового класса. Это заканчивается созданием прокси-сервера на основе этого интерфейса, из-за этого, когда приходит время для создания сопоставлений для вашего запроса, Spring MVC, вероятно, не находит ваши сопоставления из вашего компонента.

Исправлений может быть несколько:

а. Вы можете попробовать заставить прокси использовать CGLIB для ваших транзакций:

<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>

б. Вы можете использовать чистый Aspectj, либо переплетение времени загрузки, либо переплетение времени компиляции.

в. Вы можете переместить @Transactional в службу (у которой есть интерфейс) и делегировать вызов от контроллера службе, таким образом избегая @Transaction на контроллере.

person Biju Kunjummen    schedule 10.08.2012
comment
Хорошо, вероятно, поскольку создаваемые прокси-серверы CGLIB не содержат аннотаций @RequestMapping, тогда рекомендация определенно будет пунктом c выше. - person Biju Kunjummen; 10.08.2012
comment
Извините, случайно отправил предыдущий комментарий, а затем удалил его. У меня не было HomeController, расширяющего или реализующего какие-либо интерфейсы, так что, скорее всего, это не так, хотя с тех пор я. Возможно, что-то подобное происходит, когда DefaultAdvisorAutoProxyCreator создает AOP-прокси (обычный java, а не cglib) для pointcuts, к которым пытается привязать Широ? Есть ли способ указать cglib для ВСЕХ прокси? - person Danny.Parker2002; 10.08.2012
comment
О, хорошо - proxy-target-class="true" принудительно использует прокси на основе CGLIB для сценариев @Transaction. - person Biju Kunjummen; 10.08.2012
comment
Просто хотел обновить, чтобы все могли видеть, что вариант B решил мою проблему. Я пытался обойтись без использования аспекта вообще, но мне не удалось заставить RequestMappingHandlerAdapter отображать @RequestMapping до того, как Широ/Апач создал прокси. Даже при использовании cglib он не читался правильно. Однако добавление spring-aspects и использование ‹tx:annotation-driven mode=aspectj /› позволяет ему работать нормально. Спасибо за помощь! - person Danny.Parker2002; 13.08.2012