@Transactional @async и другие аннотации не работают
Раньше многие люди сталкивались с некоторыми ситуациями, когда аннотация не работает при использовании @Transactional, @Async и других аннотаций весной.
Почему эти ситуации происходят? Поскольку функции этих аннотаций фактически реализованы Spring AOP, а принципы их реализации реализуются через прокси.
JDK Dynamic Proxy
Давайте поймем основные принципы динамического прокси JDK с простым примером:
// Целевой интерфейс класса общедоступный интерфейс jdkproxytestservice {void run ();} // Целевой класс открытый класс jdkproxytestserviceimpl реализует jdkproxytestservice {public void run () {System.out.println ("Do Mo ..."); }} // proxy class public class testjdkproxy реализует vlocationhandler {private object targetobject; // Прокси -целевой объект // Создание объекта Proxy Public Object newProxy (объект TargetObject) {this.TargetObject = targetObject; return proxy.newProxyInstance (targetObject.getClass (). getClassLoader (), targetObject.getClass (). getInterfaces (), это); } // Используйте отражение для выполнения логического улучшения на исходном логическом общедоступном объекте Invoke (Прокси -прокси, метод, метод, объект [] args) бросает {// моделировать начало транзакции raffeginTransaction (); // исходный объект логики выполнения ret = method.invoke (targetObject, args); // Mock Transaction Pretragion AssumeCommitTransaction (); возврат возврата; } private void предполагать beginTransaction () {System.out.println ("Mock Transaction Start ..."); } private void assumecommitTransaction () {System.out.println ("Подчинение макетной транзакции ..."); }} // тест открытого теста класса {public static void main (string [] args) {testjdkproxy jdkproxy = new testjdkproxy (); Jdkproxytestservice proxy = (jdkproxytestservice) jdkproxy.newproxy (new jdkproxytestserviceimpl ()); proxy.run (); }}Приведенный выше пример должен быть в состоянии четко объяснить принцип динамического прокси JDK. Он использует механизм отражения для создания анонимного класса, который реализует интерфейс прокси, и вызывает Invokehandler для обработки его перед вызовом конкретного метода. Когда мы вызовываем метод через объект класса прокси, сначала мы будем называть его метод Invoke, а затем вызовуте исходный метод. Таким образом, мы можем добавить логику обработки равномерно до и после исходной логики метода.
Spring также имеет динамический прокси -метод, который является динамическим прокси -сервером CGLIB. Он загружает файл класса класса объекта прокси и обрабатывает его путем изменения своего байт -кода для генерации подклассов. Хотя методы обработки разные, идеи агентства последовательны.
Если целевой объект, являющийся доверенным, реализует интерфейс, Spring будет использовать JDK Dynamic Proxy по умолчанию. Все интерфейсы, реализованные этим целевым типом, будут оформлены. Если целевой объект не реализует какого -либо интерфейса, создается прокси CGLIB.
Сбой и разрешение аннотации Spring AOP
Основываясь на вышеуказанном анализе принципа динамического прокси, давайте посмотрим на следующие две общие проблемы:
В том же классе метод A вызовой метод B (аннотирован по методу B), а аннотация недействительна.
Для всех весенних аннотаций AOP, если Spring находит такие аннотации при сканировании бобов, он динамически построит прокси -объект.
Эта аннотация действительна, если вы хотите напрямую вызвать метод A с аннотацией через объект класса X. Поскольку в настоящее время Spring определит, что на методе, который вы собираетесь позвонить, существует аннотация AOP для вызова A.
Но предположим, что этот метод A в классе X будет вызывать метод B с аннотацией, и вы все еще хотите вызвать метод A через объект класса X, затем аннотация на методе B является недействительной. Поскольку Spring определяет, что A Call не имеет аннотации, исходный объект все еще используется, а не прокси -объект. Когда вызовы B затем, аннотация метода B в исходном объекте, конечно, недействительна.
Решение:
Самый простой способ - это, конечно, сделать методы A и B, не имеют зависимостей и могут напрямую вызов метода B через объект класса X.
Но много раз наша логика может быть не очень хорошо написана таким образом, поэтому есть другой метод: найти способ вручную получить объект прокси.
Класс AopContext имеет метод CurrentProxy (), который может напрямую получить прокси -объект текущего класса. Тогда приведенный выше пример можно решить так:
// Метод вызова B Внутренний Метод A // 1. Вызов B напрямую, аннотация недействительна. B () // 2. Получить объект класса Proxy и вызов B. ((x) aopcontext.currentproxy ()). B ()
Объект @autowired является нулевым в методе аннотации AOP
В предыдущем использовании в методе аннотации при использовании других впрыскиваемых объектов было обнаружено, что объект не был введен, и он был нулевым.
Наконец, было обнаружено, что причина этого была в том, что метод был частным. Поскольку Spring использует динамический прокси -прокси JDK или динамический прокси CGLIB, один - это класс, который реализует интерфейс, а другой реализуется посредством подклассов. Ни интерфейс, ни родительский класс, частный метод не могут присутствовать, в противном случае ни подкласс, ни класс реализации не могут быть переопределены.
Если метод является частным, то этот метод не может быть найден в прокси -процессе, вызывая проблемы при создании прокси -объектов и приводя к введению некоторых объектов.
Поэтому, если метод должен использовать аннотации AOP, установите его на непредоходное метод.
Выше всего содержание этой статьи. Я надеюсь, что это будет полезно для каждого обучения, и я надеюсь, что все будут поддерживать Wulin.com больше.