[Хорошее интервью] Практическая отладка, научит вас анализировать Spring-Aop

Spring

【Точка сухих товаров】вот【хорошее интервью] Одиннадцатая статья цикла. Прочитав эту статью, вы сможете понять принципы использования и принципы АОП в Spring, а также сможете легко ответить на вопросы, связанные с АОП, на собеседовании. Что еще более важно, у многих людей действительно большая голова, когда они смотрят исходный код. На этот раз я покажу вам весь процесс отладки чтения исходного кода шаг за шагом. Надеюсь, это вам поможет. .

Предыдущая статья относительно легкая, сатирическое описание происхождения и практическое применение AOP [Portal:Tickets.WeChat.QQ.com/Yes/He Q lo-LF_H…], я обещал вам добавить статью об анализе соответствующих принципов, в которой шаг за шагом будет объяснено, что сделал SpringAop, и соответствующие принципы.

главная предпосылка

Прочитав последнюю статью, вы знаете, что я определил здесь раздел

图片描述

Этот аспект определяет PointCut, Advice и JoinPoint, а затем определяет бизнес-класс BuyService и бизнес-класс ChatService.Далее я объясню, что делает SpringAop в режиме отслеживания исходного кода.

Что сделал Spring Aop [Начать отслеживание и чтение исходного кода]

Сначала дайте основной класс

2

Вы можете видеть, что здесь я использую AnnotationConfigApplicationContext, объясните

AnnotationConfigApplicationContext — это контейнер для управления аннотированными bean-компонентами, поэтому я могу использовать этот контейнер для получения экземпляров моих классов с аннотациями @Service.

После точки останова запустим программу, мы увидим, что экземпляр TestDemo ведет себя так в идее

3

Экземпляр BuyService отличается

4

Мы видим, что BuyService — это экземпляр, улучшенный SpringCGLIB, тогда возникает проблема.

  • Почему Buyservice расширено и TestDemo нет?
  • Что такое SpringCGLIB?
  • Когда Spring генерирует защищенный экземпляр?

На эти вопросы давайте шаг за шагом найдем ответ в исходном коде Spring.

Почему BuyService улучшен, а TestDemo нет?

Этот вопрос относительно прост, мы можем вернуться к моему определению среза выше.

5

Из кода видно, что определенный мной pointcut является классом с именем *Service, и TestDemo явно не соответствует этому параметру, поэтому TestDemo избежал участи усиления.

Что такое SpringCGLIB?

CGLIB на самом деле представляет собой технологию реализации динамического прокси, которая использует пакет с открытым исходным кодом ASM, сначала загружает файл класса класса прокси-объекта, а затем модифицирует его байт-код и генерирует подклассы. Объединив демонстрацию для ее интерпретации, SpringCGLIB сначала загрузит BuyService в память, а затем сгенерирует подкласс BuyService, изменив байт-код.Этот подкласс является расширенным BuyService, а расширенный экземпляр, показанный выше, является экземплярами подклассов.

Когда Spring генерирует защищенный экземпляр?

Это удивительно Прежде всего, мы должны начать с того, как Spring загружает срезы.

【Время на обдумывание】Почему я решил начать с кусочков? Причина очень проста: Spring знает, какие классы усиливать, потому что он обнаруживает срез и анализирует его.

6

Первым шагом в обработке слайсов является добавление аннотации @Aspect.Любой, кто изучал аннотации, знает, что функция аннотаций больше для распознавания знаков, то есть для того, чтобы сообщить Spring, что этому классу нужно выполнить специальную обработку, поэтому мы можно основываться на этом понимании. , инвертировать место, где используется аннотация

7

Как видно с скриншота, анти-настраиваю I после @Aspect нацелена на функцию HASASPECTANTATIONATIONATIONATIONATIONATIONATIONATIONATIONATIONATIONATIORFATORFFFFFFFFFFFFFFFFFFFACTORFFFFFFFFFFFFFFORFFFFFFFFFORFFFFFFFFFFFORFFFFFORFFFFFFORFACTORAFFORFFORFACTORAFFORFACTORAFFORFORFORFFORFORFORFORFORFORTORY. добавлено условие clazz == authaspect.class, перезапустить

8

Мы видим, что точка останова действительно достигнута, и можем сделать вывод, что моя догадка верна. Давайте сначала посмотрим, что произошло после точки останова, а затем посмотрим, где выполнялось сканирование. Нажмите F8 в точке останова, чтобы продолжить вниз, и, наконец, найдите

13

Правильно, вы можете видеть, что объект Advisor наконец создан и помещен в AdvisorsCache в BeanFactoryAspectJAdvisorsBuilder,Это означает, что Spring в конечном итоге создаст класс, аннотированный @Aspect, в объект Advisor и сохранит его в BeanFactoryAspectJAdvisorsBuilder.advisorsCache.

Теперь давайте посмотрим, где сканируются связанные классы, аннотированные @Aspect.На этот раз моя точка останова находится там, где помещается AdvisorsCache в вызовах BeanFactoryAspectJAdvisorsBuilder.

【Время на обдумывание】Почему я решил нарушить точку, в которую помещаются вызовы AdvisorsCache? Причина очень проста, потому что мы проанализировали выше, что аннотированный класс @Aspect встроен в объект Advisor и сохранен в BeanFactoryAspectJAdvisorsBuilder.advisorsCache, и я знаю, что есть только одно место для инверсии, поэтому я могу сделать вывод, что здесь можно узнать точку останова Где выполнялась операция сканирования.

14

После прохождения точки останова я вижу из панели кадров идеи

19

Да, сканер, сканирующий аннотацию @Aspect, — это класс AbstractAutoProxyCreator.

11
12

Мы видим, что AbstractAutoProxyCreator, наконец, реализует интерфейс InstantiationAwareBeanPostProcessor.

【Время на обдумывание】Что делает этот интерфейс? Подробнее читайте в статье, которую я написал некоторое время назад:Tickets.WeChat.QQ.com/Yes/Day 2o EQ sap6…

Теперь мы нашли место для сканирования аннотаций, а также увидели, что объект Advisor наконец сгенерирован и помещен в AdvisorsCache в BeanFactoryAspectJAdvisorsBuilder, так когда же Spring сгенерирует расширенный экземпляр? Моя следующая точка входа — интерфейс postProcessAfterInitialization в AbstractAutoProxyCreator.

【Время на обдумывание】Причина, по которой AbstractAutoProxyCreator выбран в качестве точки входа, заключается в том, что из именования видно, что SpringAop использует его для создания прокси [расширенных] объектов, а также потому, что SpringCGLIB сначала загружает целевой класс в память, а затем генерирует его, изменяя байт-код Подкласс целевого класса, поэтому я предполагаю, что усиление защиты происходит, когда postProcessAfterInitialization запускается после создания экземпляра целевого класса.

Поэтому я сделал точку останова в интерфейсе postProcessAfterInitialization и добавил условия отладки.

14

Вы можете видеть, что здесь я сломал класс ChatService.

【Время на обдумывание】Зачем специальная точка останова ChatService этому классу? Причина, по которой я специально нахожу этот класс, заключается в том, что целевой класс моего аспекта содержит ChatService, Находя этот класс, мы можем шаг за шагом фиксировать операции расширения Spring.

Мы видим, что сгенерированный расширенный объект скрыт в файле wrapIfNecessary.

【Время на обдумывание】Почему я знаю, что сгенерированный расширенный объект скрыт в wrapIfNecessary? Поскольку в процессе отладки я обнаружил, что после вызова интерфейса wrapIfNecessary возвращаемый объект является расширенным объектом.

Итак, вопрос в том, почему Spring знает, что класс ChatService нуждается в улучшении? Мы можем углубиться из wrapIfNecessary и через отладку увидеть

16

Здесь соответствующий Advisor будет получен из AdvisorsCache в соответствии с aspectName. После получения советника это место для фильтрации.Вернитесь через F8, и вы увидите, что место для фильтрации находится в интерфейсе AopUtils.canApply.

17

Видно, что переданный здесь targetClass соответствует требованиям аспекта, поэтому можно создать расширенный объект. Теперь давайте посмотрим, где на самом деле генерируются объекты армирования.

18

Мы видим, что в функции createProxy класса AbstractAutoProxyCreator наконец-то будет создан расширенный chatService. Так что же делает createProxy? Проходя точки останова слой за слоем, мы обнаруживаем, что, наконец, достигнем

18

С помощью анализа исходного кода мы обнаружили, что функция createAopProxy была вызвана, когда AbstractAutoProxyCreator построил расширенный объект. Дело в том, что мы можем видеть, что targetClass, то есть ChatService, вынес решение. Если targetClass имеет интерфейс реализации или targetClass является подклассом Proxy. Тогда для реализации AOP используется динамический прокси JDK, в противном случае для реализации динамического прокси будет использоваться CGLIB.

Так есть ли разница между динамическим прокси, реализованным JDK, и динамическим прокси, реализованным CGLIB?Прежде всего, динамические прокси можно разделить на два типа: динамические прокси JDK и динамические прокси CGLIB. Из текста также видно, что динамический прокси JDK используется только тогда, когда у целевого класса есть интерфейс, поскольку динамический прокси JDK не может проксировать класс без интерфейса. Динамический прокси-сервер JDK использует механизм отражения для создания анонимного класса, реализующего интерфейс прокси-сервера, в то время как CGLIB реализует прокси-сервер для класса, в основном создавая подкласс для указанного класса и перезаписывая методы.

Прокси-режим механизма реализации Aop

Первоначально хотел закончить статью об анализе отслеживания исходного кода Aop и режиме прокси механизма реализации Aop, но обнаружил, что анализ отслеживания исходного кода занимает много места, поэтому нет другого выхода, кроме как открыть другую статью для описания Режим прокси механизма реализации Aop, с нетерпением жду следующей статьи.

Краткое содержание статьи

Это видно из приведенного выше чтения и анализа исходного кода.

  • Усовершенствованный экземпляр ChatService создается после создания экземпляра ChatService, то есть после AbstractAutoProxyCreator.postProcessAfterInitialization.
  • Причина, по которой Spring может определить необходимость усиления экземпляра ChatService, заключается в том, что перед этим шагом Spring использует AbstractAutoProxyCreator для сканирования класса, аннотированного @Aspect, создает объект Advisor и помещает его в AdvisorCache.
  • Класс ChatService идентифицируется после извлечения из AdvisorsCache, и используется AopUtils.canApply. После того, как идентификация будет передана, она перейдет в функцию AbstractAutoProxyCreator.createProxy и сконструирует из нее реальный расширенный объект.
  • При построении расширенного объекта используется defaultAopProxyFactory.createAopProxy и оценивается целевой класс.Если targetClass имеет интерфейс реализации или targetClass является подклассом Proxy, то для реализации AOP используется динамический прокси JDK. динамический прокси с использованием CGLIB.

сказать слово

Любой, кто знает меня, знает, что статьи, которые я пишу, потратят много времени на сортировку соответствующих материалов, и я осмелюсь написать соответствующие статьи после того, как полностью их разберусь. Цель очень проста. Я хочу узнать больше вещей таким образом. , а затем использовать мои собственные слова и понимание для вывода. Друг сказал, что я слишком медленно публикую, и посоветовал мне публиковать горячие статьи, чтобы я мог быстрее увеличить количество подписчиков. Я отказался. Я хочу сохранить свое первоначальное намерение и производить только после обучения. Я не хочу тратить время на себя растущая статья.

Спасибо моим друзьям, которые следили за мной так долго, спасибо, что не прошли тест из-за моей низкой производительности, и надеюсь расти вместе! ! !

logo