《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门,即可获取!
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 2.拿到我们被代理的对象实例
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}
// Get the interception chain for this method.
// 3.获取拦截器链:例如使用@Around注解时会找到AspectJAroundAdvice,还有ExposeInvocationInterceptor
List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// 4.检查我们是否有任何拦截器(advice)。 如果没有,直接反射调用目标,并避免创建MethodInvocation。
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
// 5.不存在拦截器链,则直接进行反射调用
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
} else {
// We need to create a method invocation…
// 6.如果存在拦截器,则创建一个ReflectiveMethodInvocation:代理对象、被代理对象、方法、参数、
// 被代理对象的Class、拦截器链作为参数创建ReflectiveMethodInvocation
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
// 7.触发ReflectiveMethodInvocation的执行方法
retVal = invocation.proceed();
}
// Massage return value if necessary.
// 8.必要时转换返回值
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned “this” and the return type of the method
// is type-compatible. Note that we can’t help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
} else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
} finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
3.获取拦截器链:使用 @Around 注解时会找到 AspectJAroundAdvice,还有 ExposeInvocationInterceptor,其中 ExposeInvocationInterceptor 在前,AspectJAroundAdvice 在后。
6.如果存在拦截器,则创建一个 ReflectiveMethodInvocation,代理对象、被代理对象、方法、参数、被代理对象的 Class、拦截器链作为参数。这边 ReflectiveMethodInvocation 已经持有了被代理对象、方法、参数,后续就可以直接使用反射来调用被代理的方法了,见代码块1。
7.触发 ReflectiveMethodInvocation 的执行方法,见代码块2。
代码块1:ReflectiveMethodInvocation 构造函数
protected ReflectiveMethodInvocation(
Object proxy, Object target, Method method, Object[] arguments,
Class<?> targetClass, List interceptorsAndDynamicMethodMatchers) {
this.proxy = proxy;
this.target = target;
this.targetClass = targetClass;
this.method = BridgeMethodResolver.findBridgedMethod(method);
this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
}
代码块2:ReflectiveMethodInvocation#proceed()
@Override
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
// 1.如果所有拦截器都执行完毕(index是从-1开始,所以跟size - 1比较),则直接使用反射调用连接点(也就是我们原本的方法)
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 2.每次调用时,将索引的值递增,并通过索引拿到要执行的拦截器
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// 3.判断拦截器是否为InterceptorAndDynamicMethodMatcher类型(动态方法匹配拦截器)
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
// 进行动态匹配。在此评估动态方法匹配器:静态部件已经过评估并且发现匹配。
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
} else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
// 动态匹配失败。跳过此拦截器并调用链中的下一个。
return proceed();
}
} else {
// It’s an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
// 4.只是一个普通的拦截器,则触发拦截器链责任链的调用,并且参数为ReflectiveMethodInvocation本身
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
该方法是一个责任链的方法,会按索引执行所有的拦截器。
1.如果所有拦截器都执行完毕(index是从-1开始,所以跟size - 1比较),则直接使用反射调用连接点(也就是我们原本的方法),见代码块3。
4.只是一个普通的拦截器,则直接调用它,参数为自己本身,在本文的例子,interceptorsAndDynamicMethodMatchers 有两个拦截器:ExposeInvocationInterceptor 在前,AspectJAroundAdvice 在后,因此首先会触发 ExposeInvocationInterceptor 的 invoke 方法,见代码块4。
代码块3:invokeJoinpoint()
protected Object invokeJoinpoint() throws Throwable {
// 反射执行连接点,也就是原方法,target为被代理的对象实例、method为执行的方法、arguments为方法参数
return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}
public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
throws Throwable {
// Use reflection to invoke the method.
try {
// 使用反射调用方法
ReflectionUtils.makeAccessible(method);
return method.invoke(target, args);
} catch (InvocationTargetException ex) {
// Invoked method threw a checked exception.
// We must rethrow it. The client won’t see the interceptor.
throw ex.getTargetException();
} catch (IllegalArgumentException ex) {
throw new AopInvocationException(“AOP configuration seems to be invalid: tried calling method [” +
method + “] on target [” + target + “]”, ex);
} catch (IllegalAccessException ex) {
throw new AopInvocationException(“Could not access method [” + method + “]”, ex);
}
}
代码块4:ExposeInvocationInterceptor#invoke
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = invocation.get();
// 1.设置为当前的MethodInvocation
invocation.set(mi);
try {
// 2.继续进入链中的下一个拦截器。
return mi.proceed();
} finally {
// 3.执行结束设置回原来的MethodInvocation
invocation.set(oldInvocation);
}
}
2.继续进入链中的下一个拦截器,该方法会回到代码块1,从而拿到下一个拦截器,并触发其 invoke 方法,在本例中也就是:AspectJAroundAdvice#invoke,见代码块5。
代码块5:AspectJAroundAdvice#invoke
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
// 1.这边的mi就是我们的ReflectiveMethodInvocation,
// ReflectiveMethodInvocation实现了ProxyMethodInvocation接口,所以这边肯定通过校验
if (!(mi instanceof ProxyMethodInvocation)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
}
// 2.将mi直接强转成ProxyMethodInvocation,mi持有代理类实例proxy、被代理类实例target、被代理的方法method等
ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
// 3.将pmi封装层MethodInvocationProceedingJoinPoint(直接持有入参mi,也就是ReflectiveMethodInvocation的引用)
ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
// 4.拿到pointcut的表达式
JoinPointMatch jpm = getJoinPointMatch(pmi);
// 5.调用增强方法
return invokeAdviceMethod(pjp, jpm, null, null);
}
5.调用增强方法,见代码块6。
代码块6:invokeAdviceMethod
protected Object invokeAdviceMethod(JoinPoint jp, JoinPointMatch jpMatch, Object returnValue, Throwable t)
throws Throwable {
// 1.argBinding:获取方法执行连接点处的参数
// 2.invokeAdviceMethodWithGivenArgs:使用给定的参数调用增强方法
return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));
}
1.获取方法执行连接点处的参数,见代码块7。
2.使用 argBinding 方法返回的参数调用增强方法,在本文给出的例子中,也就是 LogInterceptor 中被 @Around 修饰的 around(ProceedingJoinPoint pjp) 方法,见代码块8。
代码块7:argBinding
protected Object[] argBinding(JoinPoint jp, JoinPointMatch jpMatch, Object returnValue, Throwable ex) {
calculateArgumentBindings();
// AMC start
Object[] adviceInvocationArgs = new Object[this.parameterTypes.length];
int numBound = 0;
if (this.joinPointArgumentIndex != -1) {
// 1.如果存在连接点参数,则将jp添加到调用参数
// 当使用@Around时就有参数;使用@Before、@After时就没有参数
adviceInvocationArgs[this.joinPointArgumentIndex] = jp;
numBound++;
} else if (this.joinPointStaticPartArgumentIndex != -1) {
adviceInvocationArgs[this.joinPointStaticPartArgumentIndex] = jp.getStaticPart();
numBound++;
}
if (!CollectionUtils.isEmpty(this.argumentBindings)) {
// binding from pointcut match
// 2.使用pointcut匹配绑定
if (jpMatch != null) {
PointcutParameter[] parameterBindings = jpMatch.getParameterBindings();
for (PointcutParameter parameter : parameterBindings) {
String name = parameter.getName();
Integer index = this.argumentBindings.get(name);
adviceInvocationArgs[index] = parameter.getBinding();
numBound++;
}
}
// binding from returning clause
// 3.用于绑定@AfterReturing中的returning参数
if (this.returningName != null) {
Integer index = this.argumentBindings.get(this.returningName);
adviceInvocationArgs[index] = returnValue;
numBound++;
}
// binding from thrown exception
// 4.用于绑定@AfterThrowing中的throwing参数
if (this.throwingName != null) {
Integer index = this.argumentBindings.get(this.throwingName);
adviceInvocationArgs[index] = ex;
numBound++;
}
}
if (numBound != this.parameterTypes.length) {
throw new IllegalStateException("Required to bind " + this.parameterTypes.length +
" arguments, but only bound " + numBound + " (JoinPointMatch " +
(jpMatch == null ? “was NOT” : “WAS”) + " bound in invocation)");
}
return adviceInvocationArgs;
}
1.如果存在连接点参数,则将 jp 添加到增强方法的参数数组,对于 @Around 来说,这边的 jp 就是代码块5中的入参 mi,也就是我们之前创建的 ReflectiveMethodInvocation 对象。所以,当使用 @Around 时,这边返回的增强方法的参数数组持有的是 ReflectiveMethodInvocation 对象。
代码块8:invokeAdviceMethodWithGivenArgs
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
Object[] actualArgs = args;
// 1.如果增强方法没有参数,则将actualArgs赋值为null
if (this.aspectJAdviceMethod.getParameterTypes().length == 0) {
actualArgs = null;
}
try {
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
// TODO AopUtils.invokeJoinpointUsingReflection
// 2.反射执行增强方法
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
} catch (IllegalArgumentException ex) {
throw new AopInvocationException(“Mismatch on arguments to advice method [” +
this.aspectJAdviceMethod + “]; pointcut expression [” +
this.pointcut.getPointcutExpression() + “]”, ex);
} catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
2.反射执行增强方法,对于本文给出的例子,这边会直接走到 LogInterceptor 中被 @Around 修饰的 around(ProceedingJoinPoint pjp) 方法,该方法会执行一些增强逻辑,最终执行 “Object result = pjp.proceed()”。
通过代码块6和代码块7我们知道,这边的 pjp 就是我们之前创建的 ReflectiveMethodInvocation 对象,所以这边会再次调用 ReflectiveMethodInvocation 对象的 process() 方法,也就是回到代码块2。此时我们的拦截器都已经执行完毕,因此会走到 invokeJoinpoint() 方法,通过反射执行我们被代理的方法,也就是 getName(String name) 方法。
最后
小编精心为大家准备了一手资料
以上Java高级架构资料、源码、笔记、视频。Dubbo、Redis、设计模式、Netty、zookeeper、Spring cloud、分布式、高并发等架构技术
【附】架构书籍
- BAT面试的20道高频数据库问题解析
- Java面试宝典
- Netty实战
- 算法
BATJ面试要点及Java架构师进阶资料
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门,即可获取!
用 ReflectiveMethodInvocation 对象的 process() 方法,也就是回到代码块2。此时我们的拦截器都已经执行完毕,因此会走到 invokeJoinpoint() 方法,通过反射执行我们被代理的方法,也就是 getName(String name) 方法。
最后
小编精心为大家准备了一手资料
[外链图片转存中…(img-i99l4wys-1714746240487)]
[外链图片转存中…(img-XYVtU6ul-1714746240488)]
以上Java高级架构资料、源码、笔记、视频。Dubbo、Redis、设计模式、Netty、zookeeper、Spring cloud、分布式、高并发等架构技术
【附】架构书籍
- BAT面试的20道高频数据库问题解析
- Java面试宝典
- Netty实战
- 算法
[外链图片转存中…(img-8eRn7cET-1714746240488)]
BATJ面试要点及Java架构师进阶资料
[外链图片转存中…(img-ghmNnVzX-1714746240488)]
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门,即可获取!