Spring — самый популярный фреймворк в Java, в основном благодаря функциям IOC и AOP, которые он предоставляет. В этой статье будет обсуждаться реализация Spring AOP. В первом разделе будут представлены связанные концепции АОП. Если вы знакомы с ним, вы можете пропустить его. Во втором разделе, в сочетании с исходным кодом, мы познакомим вас с тем, как Spring реализует концепции АОП.
1. Концепция АОП
1.1 JoinPoint
Точка выполнения программы, в которой происходит операция плетения.
Общие типы:
-
Вызов метода: точка, в которой был вызван метод.
-
Выполнение вызова метода: время, когда метод начинает выполняться внутри.
Вызов метода находится ввызывающий объектТочка выполнения при выполнении вызова метода находится ввызываемый объектМетод запускает точку выполнения.
-
Вызов конструктора: точка, в которой вызывается конструктор объекта.
-
Выполнение вызова конструктора: точка, в которой начинается выполнение внутри конструктора объекта.
-
Набор полей: Момент, когда поле устанавливается методом установки или напрямую.
-
Поле Получить: точка доступа к полю через метод получения или напрямую.
-
Выполнение обработчика исключений: Точка, в которой выполняется логика обработки исключений после создания некоторых типов исключений.
-
Инициализация класса: точка инициализации некоторого статического типа или статического блока в классе.
1.2 Pointcut
То, как выражается точка соединения.
Общие выражения:
- Непосредственно укажите имя метода, в котором находится точка соединения.
- регулярное выражение
- конкретный язык представления Pointcut
1.3 Advice
Носитель единой сквозной логики концерна, вплетенной в сквозную логику Joinpoint.
Конкретные формы:
- Before Advice: выполняется перед точкой присоединения.
-
After Advice: Выполняется после точки присоединения, подразделяется на три типа:
- After Returning Advice: выполняется после нормального завершения точки присоединения.
- After Throwing Advice: выполняется после возникновения исключения в точке соединения.
- After Finally Advice: выполняется после нормального завершения точки соединения или возникновения исключения.
- Around Advice: Оборачивает точку присоединения, выполняется до и после точки присоединения, с функциями «До консультации» и «После консультации».
- Introduction: добавление новых свойств или поведения к существующим объектам.
1.4 Aspect
Концептуальная сущность АОП, которая модульно инкапсулирует логику сквозных проблем, включая определения нескольких Pointcut и связанных рекомендаций.
1.5 Плетение и плетение
Плетение: интегрируйте сквозные аспекты модульности Aspect в систему ООП.
Weaver: используется для завершения операции ткачества.
1.6 Target
Объекты, которые вплетаются в сквозную логику в процессе плетения.
Соедините вышеприведенные 6 концепций вместе, как показано на следующем рисунке:
После понимания различных концепций АОП ниже будет представлена конкретная реализация концепций АОП в Spring.
2. Реализация весной
Как упоминалось выше, существует много типов точек соединения АОП, таких как вызов метода, выполнение метода, настройка поля, получение поля и т. д. В Spring AOP поддерживает тольковыполнение методаТипа точки присоединения, но это уже может удовлетворить 80% потребностей в разработке.Если у вас есть особые потребности, вы можете обратиться к другим продуктам АОП, таким как AspectJ. Поскольку Joinpoint включает в себя процесс времени выполнения, он эквивалентен последнему шагу в сборке всех компонентов для запуска АОП. Поэтому, представив реализацию других концепций, мы, наконец, представим реализацию Joinpoint.
2.1 Pointcut
Поскольку Spring AOP поддерживает только Joinpoint из категории выполнения метода, Pointcut необходимо определить метод, который необходимо связать, а поскольку методы в Java инкапсулированы в классы, Pointcut необходимоОпределить вплетенные классы и методы, см. его реализацию ниже.
На веснуorg.springframework.aop.Pointcut
Интерфейс определяет абстракцию верхнего уровня Pointcut.
public interface Pointcut {
// ClassFilter用于匹配被织入的类
ClassFilter getClassFilter();
// MethodMatcher用于匹配被织入的方法
MethodMatcher getMethodMatcher();
// TruePoincut的单例对象,默认匹配所有类和方法
Pointcut TRUE = TruePointcut.INSTANCE;
}
Мы видим, что,Pointcut
пройти черезClassFilter
а такжеMethodMatcher
для определения соответствующей точки соединения.Pointcut
Классы и методы определяются отдельно, чтобы иметь возможностьповторное использование. Например, есть две точки соединения типа A.fun()
метод и класс Bfun()
метод, два метода имеют одинаковую сигнатуру, только одинfun()
методMethodMatcher
объекта, для достижения цели повторного использования,ClassFilter
То же самое справедливо.
Узнайте нижеClassFilter
а такжеMethodMatcher
как соответствовать.
ClassFilter
использовать**matches
Метод ** соответствует вплетаемому классу и определяется следующим образом:
public interface ClassFilter {
// 匹配被织入的类,匹配成功返回true,失败返回false
boolean matches(Class<?> clazz);
// TrueClassFilter的单例对象,默认匹配所有类
ClassFilter TRUE = TrueClassFilter.INSTANCE;
}
MethodMatcher
также использоватьmatches
методСопоставление вплетено в метод, определяемый следующим образом:
public interface MethodMatcher {
// 匹配被织入的方法,匹配成功返回true,失败返回false
// 不考虑具体方法参数
boolean matches(Method method, Class<?> targetClass);
// 匹配被织入的方法,匹配成功返回true,失败返回false
// 考虑具体方法参数,对参数进行匹配检查
boolean matches(Method method, Class<?> targetClass, Object... args);
// 一个标志方法
// false表示不考虑参数,使用第一个matches方法匹配
// true表示考虑参数,使用第二个matches方法匹配
boolean isRuntime();
// TrueMethodMatcher的单例对象,默认匹配所有方法
MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
}
Видетьmatches
объявление метода, как вы думаете, это немного странно, вClassFilter
Разве класс уже не соответствуетMethodMatcher
изmatches
Существует также метод вClass<?> targetClass
параметр. Обратите внимание, что здесьClass<?>
Параметр типа будетне будет соответствовать, но толькодля того, чтобы найти определенный метод. Например:
public boolean matches(Method method, Class<?> targetClass) {
Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
...
}
существуетMethodMatcher
в сравнении сClassFilter
особенный вдваmatches
метод. будетсогласно сisRuntime()
Обратный результат решаетЧто звонить. а такжеMethodMatcher
потому чтоisRuntime()
на два абстрактных классаStaticMethodMatcher
(возвращает false независимо от аргументов) иDynamicMethodMatcher
(возвращает true с учетом параметров).
Pointcut
Также из-заMethodMathcer
Его можно разделить наStaticMethodMatcherPointcut
а такжеDynamicMethodMatcherPointcut
, соответствующая диаграмма классов выглядит следующим образом:
DynamicMethodMatcherPointcut
В этой статье мы не будем вводить, в основном представим три класса реализации, перечисленные на следующей диаграмме классов.
(1) NameMatchMethodPointcut
указавимя метода, которое затем напрямую сопоставляется с именем метода, а также поддерживается подстановочный знак «*».
public class NameMatchMethodPointcut extends StaticMethodMatcherPointcut implements Serializable {
// 方法名称
private List<String> mappedNames = new ArrayList<>();
// 设置方法名称
public void setMappedNames(String... mappedNames) {
this.mappedNames = new ArrayList<>(Arrays.asList(mappedNames));
}
@Override
public boolean matches(Method method, Class<?> targetClass) {
for (String mappedName : this.mappedNames) {
// 根据方法名匹配,isMatch提供“*”通配符支持
if (mappedName.equals(method.getName()) || isMatch(method.getName(), mappedName)) {
return true;
}
}
return false;
}
// ...
}
(2) JdkRegexpMethodPointcut
Внутри находится массив паттернов, указаврегулярное выражение, а затем сопоставьте с именем метода.
(3) AnnotationMappingPointcut
В зависимости от того, существует ли целевой объект указанного типааннотациясоответствовать.
2.2 Advice
Advice является носителем сквозной логики.Диаграмма интерфейсных классов Advice в Spring AOP выглядит следующим образом:
(1) Метод Перед советом
Сквозная логика будет вМетод точки присоединения выполняется до. Может использоваться для инициализации ресурсов или подготовительных работ.
public interface MethodBeforeAdvice extends BeforeAdvice {
void before(Method method, Object[] args, @Nullable Object target) throws Throwable;
}
Давайте реализуемMethodBeforeAdvice
, и увидеть его эффект.
public class PrepareResourceBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("准备资源");
}
}
определитьITask
интерфейс:
public interface ITask {
void execute();
}
ITask
класс реализацииMockTask
:
public class MockTask implements ITask {
@Override
public void execute() {
System.out.println("开始执行任务");
System.out.println("任务完成");
}
}
Основной метод заключается в следующем:ProxyFactory
,Advisor
В последующем будет введено, сначала кратко понять, черезProxyFactory
получить класс прокси,Advisor
для упаковкиPointcut
а такжеAdvice
.
public class Main {
public static void main(String[] args) {
MockTask task = new MockTask();
ProxyFactory weaver = new ProxyFactory(task);
weaver.setInterfaces(new Class[]{ITask.class});
// 内含一个NameMatchMethodPointcut
NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor();
// 指定NameMatchMethodPointcut的方法名
advisor.setMappedName("execute");
// 指定Advice
advisor.setAdvice(new PrepareResourceBeforeAdvice());
weaver.addAdvisor(advisor);
ITask proxyObject = (ITask) weaver.getProxy();
proxyObject.execute();
}
}
/** output:
准备资源
开始执行任务
任务完成
**/
Видно, что прокси-объект выполняетсяproxyObject
изexecute
метод, выполнить первымPrepareResourceBeforeAdvice
серединаbefore
метод.
(2) ThrowsAdvice
Сквозная логика будет вВыполняется, когда метод Joinpoint выдает исключение. Может использоваться для нештатной работы мониторинга.
Интерфейс ThrowsAdvice не определяет никаких методов, но согласовано, что при реализации этого интерфейсаОпределенный метод должен соответствовать следующим правилам:
void afterThrowing([Method, args, target], ThrowableSubclass)
Первые три параметра — это связанная информация о точке присоединения, которую можно опустить.ThrowableSubclass
Указывает тип исключения, которое необходимо перехватить.
Например, вы можете определить несколькоafterThrowing
Метод перехватывает исключение:
public class ExceptionMonitorThrowsAdvice implements ThrowsAdvice {
public void afterThrowing(Throwable t) {
System.out.println("发生【普通异常】");
}
public void afterThrowing(RuntimeException e) {
System.out.println("发生【运行时异常】");
}
public void afterThrowing(Method m, Object[] args, Object target, ApplicationException e) {
System.out.println(target.getClass() + m.getName() + "发生【应用异常】");
}
}
изменитьMockTask
Содержание:
public class MockTask implements ITask {
@Override
public void execute() {
System.out.println("开始执行任务");
// 抛出一个自定义的应用异常
throw new ApplicationException();
// System.out.println("任务完成");
}
}
изменитьMain
Содержание:
public class Main {
public static void main(String[] args) {
MockTask task = new MockTask();
ProxyFactory weaver = new ProxyFactory(task);
weaver.setInterfaces(new Class[]{ITask.class});
NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor();
advisor.setMappedName("execute");
// 指定异常监控Advice
advisor.setAdvice(new ExceptionMonitorThrowsAdvice());
weaver.addAdvisor(advisor);
ITask proxyObject = (ITask) weaver.getProxy();
proxyObject.execute();
}
}
/** output:
开始执行任务
class com.chaycao.spring.aop.MockTaskexecute发生【应用异常】
**/
когда брошеноApplicationException
когда соответствующийafterThrowing
метод захвачен.
(3) Совет после возврата
Сквозная логика будет вВыполняется, когда метод Joinpoint возвращается нормально. Может использоваться для очистки ресурсов.
public interface AfterReturningAdvice extends AfterAdvice {
void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable;
}
Реализуйте совет по очистке ресурсов:
public class ResourceCleanAfterReturningAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("资源清理");
}
}
ИсправлятьMockTask
Для успешного нормального выполнения изменитеMain
указан методResourceCLeanAfterReturningAdvice
, эффект следующий:
/** output:
开始执行任务
任务完成
资源清理
**/
(4) МетодПерехватчик
Эквивалент Around Advice, функция очень мощная,Может выполняться до и после метода Joinpoint и даже изменять возвращаемое значение.. Он определяется следующим образом:
public interface MethodInterceptor extends Interceptor {
Object invoke(MethodInvocation invocation) throws Throwable;
}
MethodInvocation
правдаMethod
пакет, черезproceed()
сделать вызов метода. Вот пример:
public class AroundMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("准备资源");
try {
return invocation.proceed();
} catch (Exception e) {
System.out.println("监控异常");
return null;
} finally {
System.out.println("资源清理");
}
}
}
Реализованный выше метод invoke реализует сразу все три упомянутые выше функции.
Вышеупомянутые четыре типа рекомендаций будут действовать для всех экземпляров целевого класса объектов и называются рекомендациями для каждого класса. Существует также тип Advice для каждого экземпляра, который может добавлять новые свойства или поведение к экземпляру, что является введением, упомянутым в первом разделе.
(5) Введение
Весна - целевой объектДобавить новые свойства или поведения,необходимостьОбъявить интерфейс и класс его реализации, то черезперехватчикВплетает определение интерфейса и реализацию реализующего класса в целевой объект. будем знакомыDelegatingIntroductionInterceptor
, который действует как перехватчик и делегирует класс реализации при вызове нового поведения.
Например, если вы хотитеMockTask
Улучшение вышеизложенного, но без изменения объявления класса, может объявить новый интерфейсIReinfore
:
public interface IReinforce {
String name = "增强器";
void fun();
}
Затем объявите класс реализации интерфейса:
public class ReinforeImpl implements IReinforce {
@Override
public void fun() {
System.out.println("我变强了,能执行fun方法了");
}
}
Измените основной метод:
public class Main {
public static void main(String[] args) {
MockTask task = new MockTask();
ProxyFactory weaver = new ProxyFactory(task);
weaver.setInterfaces(new Class[]{ITask.class});
// 为拦截器指定需要委托的实现类的实例
DelegatingIntroductionInterceptor delegatingIntroductionInterceptor =
new DelegatingIntroductionInterceptor(new ReinforeImpl());
weaver.addAdvice(delegatingIntroductionInterceptor);
ITask proxyObject = (ITask) weaver.getProxy();
proxyObject.execute();
// 使用IReinfore接口调用新的属性和行为
IReinforce reinforeProxyObject = (IReinforce) weaver.getProxy();
System.out.println("通过使用" + reinforeProxyObject.name);
reinforeProxyObject.fun();
}
}
/** output:
开始执行任务
任务完成
通过使用增强器
我变强了,能执行fun方法了
**/
прокси-объектproxyObject
Затем через перехватчик вы можете использоватьReinforeImpl
Реализовать методы класса.
2.3 Aspect
Используется веснойAdvisor
Представляет Аспект, за исключением того, чтоAdvisor
обычно держат толькоОдинPointcut
а такжеОдинAdvice
.Advisor
согласно сAdvice
разделен наPointcutAdvisor
а такжеIntroductionAdvisor
.
2.3.1 PointcutAdvisor
общийPointcutAdvisor
Классы реализации:
(1) DefaultPointcutAdvisor
Самый общий класс реализации, который можно указатьлюбого типаPointcut
а такжеКромеIntroduction
любого типа, кромеAdvice
.
Pointcut pointcut = ...; // 任意类型的Pointcut
Advice advice = ...; // 除了Introduction外的任意类型Advice
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
advisor.setPointcut(pointcut);
advisor.setAdvice(advice);
(2) NameMatchMethodPointcutAdvisor
В коде, который демонстрирует Advice, он был кратко представлен,есть один внутриNameMatchMethodPointcut
экземпляр, может содержать кромеIntroduction
любого типа, кромеAdvice
.
Advice advice = ...; // 除了Introduction外的任意类型Advice
NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor();
advisor.setMappedName("execute");
advisor.setAdvice(advice);
(3) советник RegexpMethodPointcutAdvisor
есть один внутриRegexpMethodPointcut
пример.
2.3.2 IntroductionAdvisor
может поддерживать только перехват на уровне класса, иIntroduction
ТипAdvice
. Класс реализации имеетDefaultIntroductionAdvisor
.
DelegatingIntroductionInterceptor introductionInterceptor =
new DelegatingIntroductionInterceptor(new ReinforeImpl());
DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(introductionInterceptor, IReinforce.class);
2.4 Плетение и плетение
В коде, который демонстрирует Advice, мы используемProxyFactory
как ткач
MockTask task = new MockTask();
// 织入器
ProxyFactory weaver = new ProxyFactory(task);
weaver.setInterfaces(new Class[]{ITask.class});
NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor();
advisor.setMappedName("execute");
advisor.setAdvice(new PrepareResourceBeforeAdvice());
weaver.addAdvisor(advisor);
// 织入,返回代理对象
ITask proxyObject = (ITask) weaver.getProxy();
proxyObject.execute();
ProxyFactory
Способы создания прокси-объектов следующие:
- Если целевой класс реализует некоторый интерфейс, по умолчаниюДинамический проксигенерировать.
- Если целевой класс не реализует интерфейс, по умолчаниюCGLIBгенерировать.
- также можетустановить напрямую
ProxyFactory
Способ его создания, даже если интерфейс реализован, CGLIB можно использовать.
В предыдущем демонстрационном коде мы не запускали контейнер Spring, то есть не использовали функцию Spring IOC, а использовали Spring AOP самостоятельно. Так как же Spring AOP интегрируется со Spring IOC? Это наиболее часто используемый метод интеграции Spring.FactoryBean
.
ProxyFactoryBean
наследоватьProxyFactory
родительский классProxyCreatorSupport
, с возможностью создания прокси-классов, при реализацииFactoryBean
интерфейс, при прохожденииgetObject
Когда метод получает bean-компонент, он получает прокси-класс.
2.5 Target
В предыдущем демонстрационном коде мы напрямуюProxyFactory
Укажите объект в качестве цели. существуетProxyFactoryBean
можно использовать не только таким образом, но иTargetSource
указано в форме.
TargetSource
Это эквивалентно слою инкапсуляции для объекта,ProxyFactoryBean
пройдешьTargetSource
изgetTarget
метод получения целевого объекта. Итак, мы можем пройтиgetTarget
путь кУправляйте полученным целевым объектом.TargetSource
Несколько классов реализации:
(1) SingletonTargetSource
Очень просто, только один целевой объект хранится внутри и возвращается напрямую. Эффект тот же, что и при прямом указании объекта.
(2) ПрототипТаржетСаурце
Каждый раз будет возвращаться новый экземпляр целевого объекта.
(3) HotSwappableTartgetSource
Во время выполнения конкретная реализация класса целевого объекта динамически заменяется в соответствии с определенными условиями. Например, когда один источник данных зависает, вы можете переключиться на другой.
(4) CommonsPool2TargetSource
Возвращает ограниченное количество экземпляров целевого объекта, аналогично пулу объектов.
(5) ThreadLocalTargetSource
Предоставляйте разные целевые объекты для разных вызовов потоков
2.6 Joinpoint
Наконец, достигнув конечной точки соединения, мы используем следующий пример, чтобы понять рабочий механизм точки соединения.
MockTask task = new MockTask();
ProxyFactory weaver = new ProxyFactory(task);
weaver.setInterfaces(new Class[]{ITask.class});
PrepareResourceBeforeAdvice beforeAdvice = new PrepareResourceBeforeAdvice();
ResourceCleanAfterReturningAdvice afterAdvice = new ResourceCleanAfterReturningAdvice();
weaver.addAdvice(beforeAdvice);
weaver.addAdvice(afterAdvice);
ITask proxyObject = (ITask) weaver.getProxy();
proxyObject.execute();
/** output
准备资源
开始执行任务
任务完成
资源清理
**/
мы знаемgetProxy
создаст динамический проксиITask
класс интерфейса, затемexecute
Как внутренности метода выполняются в первую очередьbeforeAdvice
изbefore
метод, затем выполнитеtask
изexecute
метод, выполнитьafterAdvice
изafter
метод?
Ответ генерируетсяпрокси-класссередина. В динамическом прокси логика вызова метода класса прокси определяетсяInvocationHandler
примерinvoke
метод, ответ дополнительно заблокированinvoke
метод.
В этом примереProxyFactory.getProxy
позвонюJdkDynamicAopProxy.getProxy
Получите прокси-класс.
// JdkDynamicAopProxy
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
существуетgetProxy
ЧжунвэйnewProxyInstance
изInvocationHandler
ввод параметровthis
,СейчасJdkDynamicAopProxy
только одинInvocationHandler
реализация, котораяinvoke
Методы, как показано ниже:
// JdkDynamicAopProxy
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 通过advised(创建对象时初始化)获得指定的advice
// 会将advice用相应的MethodInterceptor封装下
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 创建一个MethodInvocation
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 调用procced,开始进入拦截链(执行目标对象方法和MethodInterceptor的advice)
retVal = invocation.proceed();
}
return retVal;
}
Сначала получите указанный совет, который содержитbeforeAdvice
а такжеafterAdvice
пример, но буду использоватьMethodInterceptor
Инкапсулируйте слой для последующей цепочки перехвата.
создать еще одинRelectiveMethodInvocation
объект, наконец, черезproceed
Войдите в цепочку перехвата.
RelectiveMethodInvocation
Это реализация Joinpoint в Spring AOP.Его диаграмма классов выглядит следующим образом:
Первый взглядRelectiveMethodInvocation
конструктор:
protected ReflectiveMethodInvocation(
Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments,
@Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
this.proxy = proxy;
this.target = target;
this.targetClass = targetClass;
this.method = BridgeMethodResolver.findBridgedMethod(method);
this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
}
Выполните несколько назначений связанных свойств, а затем посмотрите наproceed
метод, как вызывать целевой объект и перехватчики.
public Object proceed() throws Throwable {
// currentInterceptorIndex从-1开始
// 当达到已调用了所有的拦截器后,通过invokeJoinpoint调用目标对象的方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 获得拦截器,调用其invoke方法
// currentInterceptorIndex加1
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
currentInterceptorIndex
начиная с -1,interceptorsAndDynamicMethodMatchers
Есть два перехватчика, и из-за вычитания 1 все условия для вызова метода целевого объекта равныcurrentInterceptorIndex
равно 1.
Во-первых, потому что-1 != 1
, будет включеноbeforeAdvice
изMethodBeforeAdviceInterceptor
пример,currentInterceptorIndex
Добавьте 1, чтобы получить 0. назовите егоinvoke
метод, потому что это предварительный совет, поэтому сначала выполнитеbeforeAdvice
изbefore
метод, затем вызовитеproceed
Введите следующее звено в цепочке перехвата.
// MethodBeforeAdviceInterceptor
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
назад сноваproceed
метод,0 != 1
, снова получая совет, на этот раз содержащийafterAdvice
изAfterReturningAdviceInterceptor
пример,currentInterceptorIndex
Добавьте 1, чтобы стать 1. назовите егоinvoke
метод, так как это After-Returning-Adivce, он будет выполнен первымproceed
Введите следующее звено в цепочке перехвата.
// AfterReturningAdviceInterceptor
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
приходи ещеproceed
метод,1 == 1
, все перехватчики были вызваны, и будут выполнены методы целевого объекта. затем возврат возвращается, обратно вinvoke
, вызовafterAdvice
изafterReturning
.
Итак, при реализации Joinpoint передайтеMethodInterceptor
Последовательное выполнение метода целевого объекта и Advice завершено.
3. Резюме
После понимания реализации Spring AOP у автора появилось более четкое представление об АОП. В процессе обучения меня больше всего заинтересовала цепочка перехвата от Joinpoint, я сначала не знал, как это реализовать, и думал, что это потрясающе 😲 . Наконец-то доучился, подвел итог, вроде бы очень просто, через перехватчикinvoke
Методы иMethodInvocation.proceed
Взаимный вызов методов (переход к следующему перехватчику). Похоже, это так. 😛