diff --git a/README.md b/README.md index a9b2393..9d07fb9 100644 --- a/README.md +++ b/README.md @@ -198,7 +198,7 @@ + Spring AOP - [JDK动态代理](spring-aop/spring-aop-jdkProxy/README.md):接口实现,动态生成代理类,处理方法调用,统一横切关注点。 - [Cglib动态代理](spring-aop/spring-aop-cglibProxy/README.md):基于字节码生成的库,无需接口,可拦截类方法并进行增强。 - - [AopProxy](spring-aop/spring-aop-aopProxy/README.md):创建和管理AOP代理对象。 + - [AopProxy](spring-aop/spring-aop-aopProxy/README.md):创建和管理AOP代理对象。 - [AopProxyFactory](spring-aop/spring-aop-aopProxyFactory/README.md):创建AOP代理工厂,支持JDK和CGLIB。 - [ProxyFactory](spring-aop/spring-aop-proxyFactory/README.md):一种便捷的方式来创建代理对象。 - [ClassFilter](spring-aop/spring-aop-classFilter/README.md):确定类是否匹配拦截条件。 diff --git a/spring-aop/spring-aop-aopProxy/README.md b/spring-aop/spring-aop-aopProxy/README.md index dd210ac..ce16af3 100644 --- a/spring-aop/spring-aop-aopProxy/README.md +++ b/spring-aop/spring-aop-aopProxy/README.md @@ -84,8 +84,7 @@ public interface AopProxy { + 使用 JDK 动态代理实现的 `AopProxy` 实现类。当目标对象实现了至少一个接口时,Spring 将使用该类创建代理对象。该类通过 Java 标准库中的 `java.lang.reflect.Proxy` 类来创建代理对象。 2. **CglibAopProxy** - - + 使用 CGLIB(Code Generation Library)动态代理实现的 `AopProxy` 实现类。当目标对象没有实现任何接口时,Spring 将使用该类创建代理对象。该类通过生成目标类的子类来创建代理对象,实现了对目标对象方法的拦截和增强。 ++ 使用 CGLIB(Code Generation Library)动态代理实现的 `AopProxy` 实现类。当目标对象没有实现任何接口时,Spring 将使用该类创建代理对象。该类通过生成目标类的子类来创建代理对象,实现了对目标对象方法的拦截和增强。 ### 六、最佳实践 @@ -191,11 +190,541 @@ Cglib Class = class com.xcs.spring.MyServiceImpl$$EnhancerBySpringCGLIB$$3c23100 doSomething method result = hello world ``` +### 七、时序图 + +#### JdkDynamicAopProxy + +~~~mermaid +sequenceDiagram +autonumber +AopProxyDemo->>JdkDynamicAopProxy:new JdkDynamicAopProxy() +JdkDynamicAopProxy->>JdkDynamicAopProxy:this.advised +JdkDynamicAopProxy->>JdkDynamicAopProxy:this.proxiedInterfaces +JdkDynamicAopProxy->>AopProxyDemo:aopProxy +AopProxyDemo->>JdkDynamicAopProxy:getProxy() +JdkDynamicAopProxy->>JdkDynamicAopProxy:getProxy(classLoader) +JdkDynamicAopProxy->>AopProxyDemo:返回代理对象 +AopProxyDemo->>$Proxy0:aopProxy.doSomething() +$Proxy0->>JdkDynamicAopProxy:invoke() +JdkDynamicAopProxy->>ReflectiveMethodInvocation:new ReflectiveMethodInvocation() +ReflectiveMethodInvocation->>JdkDynamicAopProxy:返回invocation +loop 递归拦截器 + JdkDynamicAopProxy->>ReflectiveMethodInvocation:invocation.proceed() + ReflectiveMethodInvocation->>ReflectiveMethodInvocation:invokeJoinpoint() + ReflectiveMethodInvocation->>AopUtils:invokeJoinpointUsingReflection() + AopUtils->>$Proxy0:method.invoke(target, args) +end + +~~~ + +#### CglibAopProxy + ### 七、源码分析 -暂无 +#### JdkDynamicAopProxy -### 七、常见问题 +在`org.springframework.aop.framework.JdkDynamicAopProxy#getProxy()`方法中,主要作用是返回一个代理对象,使用默认的类加载器来生成代理。 + +```java +@Override +public Object getProxy() { + return getProxy(ClassUtils.getDefaultClassLoader()); +} +``` + +在`org.springframework.aop.framework.JdkDynamicAopProxy#getProxy(java.lang.ClassLoader)`方法中,接收一个类加载器作为参数,并根据传入的类加载器和被代理的接口数组来创建一个 JDK 动态代理对象。 + +```java +@Override +public Object getProxy(@Nullable ClassLoader classLoader) { + if (logger.isTraceEnabled()) { + logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource()); + } + return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this); +} +``` + +在`org.springframework.aop.framework.JdkDynamicAopProxy#invoke`方法中,`JdkDynamicAopProxy`实现了`InvocationHandler`接口,因此可以执行`invoke`方法。在方法中,首先根据方法是否为`equals`或`hashCode`方法进行特殊处理,然后获取目标对象并获取拦截器链。接着,根据拦截器链是否为空,选择直接调用目标对象方法或者通过方法拦截器链依次执行。最后,根据方法的返回值类型进行处理,如果返回值为目标对象并且返回类型与代理类型相同,则将返回值修改为代理对象。在方法执行完毕后,确保释放目标对象并恢复旧的代理对象。 + +```java +/** + * 实现了 {@code InvocationHandler.invoke} 方法。 + *

调用者将看到目标对象抛出的异常,除非一个钩子方法抛出异常。 + */ +@Override +@Nullable +public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + // 旧的代理对象 + Object oldProxy = null; + // 是否设置了代理上下文标志 + boolean setProxyContext = false; + + // 目标源 + TargetSource targetSource = this.advised.targetSource; + // 目标对象 + Object target = null; + + try { + if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { + // 目标对象未实现 equals(Object) 方法 + return equals(args[0]); + } else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { + // 目标对象未实现 hashCode() 方法 + return hashCode(); + } else if (method.getDeclaringClass() == DecoratingProxy.class) { + // 只有 getDecoratedClass() 声明 -> 转发到代理配置 + return AopProxyUtils.ultimateTargetClass(this.advised); + } else if (!this.advised.opaque && method.getDeclaringClass().isInterface() && + method.getDeclaringClass().isAssignableFrom(Advised.class)) { + // 在代理配置上执行服务调用... + return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); + } + + Object retVal; + + if (this.advised.exposeProxy) { + // 必要时使调用可用 + oldProxy = AopContext.setCurrentProxy(proxy); + setProxyContext = true; + } + + // 尽可能晚地获取目标对象,以最小化我们“拥有”目标对象的时间,以防它来自池。 + target = targetSource.getTarget(); + Class targetClass = (target != null ? target.getClass() : null); + + // 获取此方法的拦截器链。 + List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); + + // 检查是否有任何通知。如果没有,则可以回退到直接反射调用目标,避免创建 MethodInvocation。 + if (chain.isEmpty()) { + // 我们可以跳过创建一个 MethodInvocation:直接调用目标 + // 注意,最终的调用者必须是一个 InvokerInterceptor,这样我们就知道它只是在目标上执行反射操作,而没有热交换或花哨的代理。 + Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); + retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); + } else { + // 我们需要创建一个方法调用... + MethodInvocation invocation = + new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); + // 通过拦截器链继续进行连接点。 + retVal = invocation.proceed(); + } + + // 如果需要,修改返回值。 + Class returnType = method.getReturnType(); + if (retVal != null && retVal == target && + returnType != Object.class && returnType.isInstance(proxy) && + !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { + // 特殊情况:它返回了“this”,并且方法的返回类型与之相容。 + // 请注意,如果目标在另一个返回对象中设置了对自身的引用,我们无法帮助。 + 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()) { + // 必须来自 TargetSource。 + targetSource.releaseTarget(target); + } + if (setProxyContext) { + // 恢复旧代理。 + AopContext.setCurrentProxy(oldProxy); + } + } +} +``` + +在`org.springframework.aop.framework.ReflectiveMethodInvocation#ReflectiveMethodInvocation`方法中,`ReflectiveMethodInvocation`类的构造函数,用于创建一个反射方法调用对象。它接收代理对象、目标对象、要调用的方法、方法参数、目标类以及拦截器和动态方法匹配器列表作为参数,并在构造过程中对这些参数进行初始化。 + +```java +/** + * 使用给定参数构造一个新的 ReflectiveMethodInvocation。 + * @param proxy 调用所在的代理对象 + * @param target 要调用的目标对象 + * @param method 要调用的方法 + * @param arguments 调用方法时传入的参数 + * @param targetClass 目标类,用于方法匹配器的调用 + * @param interceptorsAndDynamicMethodMatchers 应该应用的拦截器,以及需要在运行时进行评估的任何 InterceptorAndDynamicMethodMatchers。 + * 此结构中包含的 MethodMatchers 必须已经被找到并匹配,尽可能地是静态的。传递一个数组可能会快约10%,但会使代码复杂化。并且它只能用于静态切入点。 + */ +protected ReflectiveMethodInvocation( + Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments, + @Nullable 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; +} +``` + +在`org.springframework.aop.framework.ReflectiveMethodInvocation#proceed`方法中,首先,检查当前拦截器索引是否到达了链的末尾,如果是,则直接调用`invokeJoinpoint()`方法执行方法调用。如果不是末尾,获取当前拦截器或拦截器通知,并根据其类型进行不同的处理。如果是`InterceptorAndDynamicMethodMatcher`类型,则评估动态方法匹配器,如果匹配成功,则调用对应的拦截器的`invoke()`方法。如果匹配失败,则跳过此拦截器,继续调用链中的下一个拦截器。如果是普通的拦截器,则直接调用其`invoke()`方法。 + +```java +/** + * 执行方法拦截器链中的下一个拦截器或方法调用。 + * @return 方法调用的结果 + * @throws Throwable 如果执行方法调用时发生异常 + */ +@Override +@Nullable +public Object proceed() throws Throwable { + // 我们从 -1 开始索引,并尽早递增。 + if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { + return invokeJoinpoint(); + } + + // 获取当前拦截器或拦截器通知 + Object interceptorOrInterceptionAdvice = + this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); + if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { + // 在此处评估动态方法匹配器:静态部分已经被评估并确定匹配。 + InterceptorAndDynamicMethodMatcher dm = + (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; + Class targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass()); + if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) { + return dm.interceptor.invoke(this); + } else { + // 动态匹配失败。 + // 跳过此拦截器,并调用链中的下一个。 + return proceed(); + } + } else { + // 它是一个拦截器,所以我们只是调用它:在此对象构造之前,切入点将已经被静态评估。 + return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); + } +} +``` + +在`org.springframework.aop.framework.ReflectiveMethodInvocation#invokeJoinpoint`方法中,调用`AopUtils.invokeJoinpointUsingReflection`方法来实现连接点的调用,该方法接收目标对象、方法和参数,并返回连接点的结果。 + +```java +/** + * 使用反射调用连接点。 + * 子类可以重写此方法以使用自定义调用。 + * @return 连接点的返回值 + * @throws Throwable 如果调用连接点导致异常 + */ +@Nullable +protected Object invokeJoinpoint() throws Throwable { + return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments); +} +``` + +在`org.springframework.aop.support.AopUtils#invokeJoinpointUsingReflection`方法中,通过`ReflectionUtils.makeAccessible(method)`方法确保要调用的方法是可访问的。然后,使用`method.invoke(target, args)`方法调用目标对象的方法,并传入参数。 + +```java +/** + * 使用反射调用给定目标对象的方法,作为AOP方法调用的一部分。 + * @param target 目标对象 + * @param method 要调用的方法 + * @param args 方法的参数 + * @return 调用结果,如果有的话 + * @throws Throwable 如果目标方法抛出异常 + * @throws org.springframework.aop.AopInvocationException 如果发生反射错误 + */ +@Nullable +public static Object invokeJoinpointUsingReflection(@Nullable Object target, Method method, Object[] args) + throws Throwable { + + // 使用反射调用方法。 + try { + // 使方法可访问 + ReflectionUtils.makeAccessible(method); + // 调用方法 + return method.invoke(target, args); + } + catch (InvocationTargetException ex) { + // 调用的方法抛出了一个已检查的异常。 + // 我们必须重新抛出它。客户端不会看到拦截器。 + 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); + } +} +``` + +#### CglibAopProxy + +在`org.springframework.aop.framework.CglibAopProxy#getProxy()`方法中,它返回代理对象。在没有指定目标类加载器的情况下,它调用了另一个重载方法 `getProxy(null)` 来生成代理对象并返回。 + +```java +@Override +public Object getProxy() { + return getProxy(null); +} +``` + +在`org.springframework.aop.framework.CglibAopProxy#getProxy(java.lang.ClassLoader)`方法中,使用 CGLIB 动态生成代理类,并创建代理对象。首先,它检查是否启用了跟踪日志,然后获取目标类的根类,并确保目标类可用于创建代理。接着,它设置代理类的父类为目标类的根类,并根据需要添加额外的接口。在配置 CGLIB Enhancer 之后,它为代理类设置回调函数,并最终生成代理类并创建代理实例。 + +```java +@Override +public Object getProxy(@Nullable ClassLoader classLoader) { + // 如果启用了跟踪日志,则记录正在创建 CGLIB 代理的信息 + if (logger.isTraceEnabled()) { + logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource()); + } + + try { + // 获取目标类的根类 + Class rootClass = this.advised.getTargetClass(); + // 断言目标类必须可用于创建 CGLIB 代理 + Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy"); + + // 设置代理类的父类为目标类的根类 + Class proxySuperClass = rootClass; + // 如果目标类的名称包含了 CGLIB 分隔符,则将父类修改为目标类的父类,并将额外的接口添加到代理类中 + if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) { + proxySuperClass = rootClass.getSuperclass(); + // 获取额外的接口并添加到代理类中 + Class[] additionalInterfaces = rootClass.getInterfaces(); + for (Class additionalInterface : additionalInterfaces) { + this.advised.addInterface(additionalInterface); + } + } + + // 在需要时验证类,并写入日志消息 + validateClassIfNecessary(proxySuperClass, classLoader); + + // 配置 CGLIB Enhancer... + Enhancer enhancer = createEnhancer(); + // 如果指定了类加载器,则设置 Enhancer 的类加载器,并在类加载器为可重新加载时禁用缓存 + if (classLoader != null) { + enhancer.setClassLoader(classLoader); + if (classLoader instanceof SmartClassLoader && + ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) { + enhancer.setUseCache(false); + } + } + // 设置代理类的父类 + enhancer.setSuperclass(proxySuperClass); + // 设置代理类实现的接口 + enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised)); + // 设置命名策略 + enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); + // 设置策略以考虑类加载器 + enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader)); + + // 获取回调对象和对应的类型 + Callback[] callbacks = getCallbacks(rootClass); + Class[] types = new Class[callbacks.length]; + for (int x = 0; x < types.length; x++) { + types[x] = callbacks[x].getClass(); + } + // fixedInterceptorMap 只在上面的 getCallbacks 调用后才填充 + // 设置回调过滤器,用于过滤固定拦截器 + enhancer.setCallbackFilter(new ProxyCallbackFilter( + this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset)); + // 设置回调类型 + enhancer.setCallbackTypes(types); + + // 生成代理类并创建代理实例 + return createProxyClassAndInstance(enhancer, callbacks); + } catch (CodeGenerationException | IllegalArgumentException ex) { + // 如果生成代理类出现异常,则抛出 AopConfigException + throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() + + ": Common causes of this problem include using a final class or a non-visible class", ex); + } catch (Throwable ex) { + // 如果获取目标类实例失败,则抛出 AopConfigException + throw new AopConfigException("Unexpected AOP exception", ex); + } +} +``` + +在`org.springframework.aop.framework.CglibAopProxy#getCallbacks`方法中,根据代理配置的不同情况,选择不同的拦截器和分发器,并根据目标类的静态性和建议链的冻结状态进行优化选择。如果目标是静态的并且建议链是冻结的,它会通过使用固定链将AOP调用直接发送到目标来进行一些优化。最终返回一个包含所有选定回调的数组。 + +```java +private Callback[] getCallbacks(Class rootClass) throws Exception { + // 用于优化选择的参数... + boolean exposeProxy = this.advised.isExposeProxy(); + boolean isFrozen = this.advised.isFrozen(); + boolean isStatic = this.advised.getTargetSource().isStatic(); + + // 选择一个“AOP”拦截器(用于AOP调用)。 + Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised); + + // 选择一个“直接到目标”的拦截器(用于无通知的调用,但可以返回this)。 + Callback targetInterceptor; + if (exposeProxy) { + targetInterceptor = (isStatic ? + new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) : + new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource())); + } else { + targetInterceptor = (isStatic ? + new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) : + new DynamicUnadvisedInterceptor(this.advised.getTargetSource())); + } + + // 选择一个“直接到目标”的分发器(用于对静态目标的未通知调用,无法返回this)。 + Callback targetDispatcher = (isStatic ? + new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp()); + + Callback[] mainCallbacks = new Callback[] { + aopInterceptor, // 用于普通建议 + targetInterceptor, // 在优化的情况下调用目标,不考虑建议 + new SerializableNoOp(), // 对于映射到此的方法,没有覆盖 + targetDispatcher, this.advisedDispatcher, + new EqualsInterceptor(this.advised), + new HashCodeInterceptor(this.advised) + }; + + Callback[] callbacks; + + // 如果目标是静态的并且建议链被冻结, + // 则我们可以通过使用固定链将AOP调用直接发送到目标来进行一些优化。 + if (isStatic && isFrozen) { + Method[] methods = rootClass.getMethods(); + Callback[] fixedCallbacks = new Callback[methods.length]; + this.fixedInterceptorMap = CollectionUtils.newHashMap(methods.length); + + // TODO: 这里进行了一些内存优化(可以跳过没有建议的方法的创建) + for (int x = 0; x < methods.length; x++) { + Method method = methods[x]; + List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass); + fixedCallbacks[x] = new FixedChainStaticTargetInterceptor( + chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass()); + this.fixedInterceptorMap.put(method, x); + } + + // 现在将mainCallbacks和fixedCallbacks中的回调复制到callbacks数组中。 + callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length]; + System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length); + System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length); + this.fixedInterceptorOffset = mainCallbacks.length; + } else { + callbacks = mainCallbacks; + } + return callbacks; +} +``` + +在`org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept`方法中,首先,它获取目标对象和目标类,并获取与指定方法相关的拦截器链。然后,根据拦截器链和方法的特性进行适当的处理。如果拦截器链为空且方法是公共的,则直接调用目标方法,否则创建一个方法调用。最后,处理方法调用的返回值并返回结果。在方法执行过程中,还会根据配置决定是否暴露代理对象,并在必要时设置AOP上下文。最后,在finally块中释放目标对象,并在必要时恢复旧的代理对象。 + +> 在 `CglibAopProxy` 中,`DynamicAdvisedInterceptor` 是一个特殊的拦截器,它被添加到了回调数组中。当执行方法时,回调数组中的 `DynamicAdvisedInterceptor` 将拦截目标方法的调用。这个拦截器负责处理 AOP 的核心功能,例如应用通知(Advice)、织入横切逻辑等。在 `DynamicAdvisedInterceptor` 的 `intercept` 方法中,它会根据代理配置获取目标方法的拦截器链,并依次调用这些拦截器来实现 AOP 功能。 + +```java +@Override +@Nullable +public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { + // 保存旧代理对象 + Object oldProxy = null; + // 是否设置了代理上下文 + boolean setProxyContext = false; + // 目标对象 + Object target = null; + // 获取目标源 + TargetSource targetSource = this.advised.getTargetSource(); + try { + if (this.advised.exposeProxy) { + // 如果配置中允许暴露代理对象,则将当前代理对象设置为Aop上下文的当前代理对象 + oldProxy = AopContext.setCurrentProxy(proxy); + setProxyContext = true; + } + // 获取目标对象,尽可能晚地获取以最小化拥有目标的时间,以防它来自池... + target = targetSource.getTarget(); + // 目标对象的类 + Class targetClass = (target != null ? target.getClass() : null); + // 获取拦截器链 + List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); + // 方法调用返回值 + Object retVal; + // 检查是否只有一个 InvokerInterceptor:即,没有真正的建议,而只是目标的反射调用。 + if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { + // 我们可以跳过创建一个 MethodInvocation:直接调用目标。 + // 请注意,最终调用者必须是一个 InvokerInterceptor,因此我们知道它只是对目标进行了反射操作,并且没有热交换或花哨的代理。 + Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); + // 直接调用目标方法 + retVal = methodProxy.invoke(target, argsToUse); + } + else { + // 我们需要创建一个方法调用... + // 创建方法调用并执行 + retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); + } + // 处理返回类型 + retVal = processReturnType(proxy, target, method, retVal); + // 返回方法调用结果 + return retVal; + } + finally { + if (target != null && !targetSource.isStatic()) { + // 如果目标对象不是静态的,则释放目标对象 + targetSource.releaseTarget(target); + } + if (setProxyContext) { + // 恢复旧代理对象。 + AopContext.setCurrentProxy(oldProxy); // 恢复Aop上下文的当前代理对象为旧代理对象 + } + } +} +``` + +在`org.springframework.aop.framework.CglibAopProxy.CglibMethodInvocation#CglibMethodInvocation`方法中,`CglibMethodInvocation` 类的构造方法。它接收代理对象、目标对象、方法、方法参数、目标类、拦截器链和方法代理作为参数,并调用父类的构造方法进行初始化。在这个构造方法中,它会检查方法的修饰符是否为公共的且不是继承自 `java.lang.Object` 的方法,如果是,则将方法代理赋值给成员变量 `methodProxy`;否则将 `methodProxy` 设置为 `null`。 + +```java +public CglibMethodInvocation(Object proxy, @Nullable Object target, Method method, + Object[] arguments, @Nullable Class targetClass, + List interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) { + // 调用父类的构造方法,初始化方法调用 + super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers); + + // 只对公共方法且不是继承自 java.lang.Object 的方法使用方法代理 + this.methodProxy = (Modifier.isPublic(method.getModifiers()) && + method.getDeclaringClass() != Object.class && !AopUtils.isEqualsMethod(method) && + !AopUtils.isHashCodeMethod(method) && !AopUtils.isToStringMethod(method) ? + methodProxy : null); // 设置方法代理 +} +``` + +在`org.springframework.aop.framework.CglibAopProxy.CglibMethodInvocation#proceed`方法中,用于执行方法调用链。它首先尝试调用父类的 `proceed()` 方法来执行方法调用链。如果在执行过程中捕获到运行时异常,则直接抛出该异常。 + +> 调用父类的 proceed 方法执行方法调用链,请参考org.springframework.aop.framework.ReflectiveMethodInvocation#proceed + +```java +@Override +@Nullable +public Object proceed() throws Throwable { + try { + // 调用父类的 proceed 方法执行方法调用链 + return super.proceed(); + } + catch (RuntimeException ex) { + throw ex; + } + catch (Exception ex) { + if (ReflectionUtils.declaresException(getMethod(), ex.getClass()) || + KotlinDetector.isKotlinType(getMethod().getDeclaringClass())) { + // Propagate original exception if declared on the target method + // (with callers expecting it). Always propagate it for Kotlin code + // since checked exceptions do not have to be explicitly declared there. + throw ex; + } + else { + // Checked exception thrown in the interceptor but not declared on the + // target method signature -> apply an UndeclaredThrowableException, + // aligned with standard JDK dynamic proxy behavior. + throw new UndeclaredThrowableException(ex); + } + } +} +``` + +### 八、常见问题 1. **选择合适的代理方式** diff --git a/spring-aop/spring-aop-aopProxy/src/main/java/com/xcs/spring/AopProxyDemo.java b/spring-aop/spring-aop-aopProxy/src/main/java/com/xcs/spring/AopProxyDemo.java index a4df2b3..b22a987 100644 --- a/spring-aop/spring-aop-aopProxy/src/main/java/com/xcs/spring/AopProxyDemo.java +++ b/spring-aop/spring-aop-aopProxy/src/main/java/com/xcs/spring/AopProxyDemo.java @@ -8,7 +8,7 @@ import java.lang.reflect.Constructor; public class AopProxyDemo { public static void main(String[] args) throws Exception { - cglibProxy(); +// cglibProxy(); jdkProxy(); } @@ -22,12 +22,14 @@ public class AopProxyDemo { AdvisedSupport advisedSupport = new AdvisedSupport(); // 设置目标对象 advisedSupport.setTarget(new MyServiceImpl()); + // 添加拦截器 + advisedSupport.addAdvice(new MyMethodInterceptor()); // 获取CglibAopProxy的Class对象 - Class cglibClass = Class.forName("org.springframework.aop.framework.CglibAopProxy"); + Class cglibClass = Class.forName("org.springframework.aop.framework.CglibAopProxy"); // 获取CglibAopProxy的构造方法 - Constructor constructor = cglibClass.getConstructor(AdvisedSupport.class); + Constructor constructor = cglibClass.getConstructor(AdvisedSupport.class); constructor.setAccessible(true); // 使用构造方法创建CglibAopProxy实例 @@ -39,7 +41,7 @@ public class AopProxyDemo { // 输出代理对象的信息 System.out.println("Cglib Class = " + myService.getClass()); // 调用代理对象的方法 - System.out.println("doSomething method result = " + myService.doSomething()); + myService.doSomething(); } /** @@ -54,12 +56,14 @@ public class AopProxyDemo { advisedSupport.setTarget(new MyServiceImpl()); // 设置目标对象实现的接口 advisedSupport.setInterfaces(MyService.class); + // 添加拦截器 + advisedSupport.addAdvice(new MyMethodInterceptor()); // 获取JdkDynamicAopProxy的Class对象 - Class jdkClass = Class.forName("org.springframework.aop.framework.JdkDynamicAopProxy"); + Class jdkClass = Class.forName("org.springframework.aop.framework.JdkDynamicAopProxy"); // 获取JdkDynamicAopProxy的构造方法 - Constructor constructor = jdkClass.getConstructor(AdvisedSupport.class); + Constructor constructor = jdkClass.getConstructor(AdvisedSupport.class); constructor.setAccessible(true); // 使用构造方法创建JdkDynamicAopProxy实例 @@ -71,6 +75,6 @@ public class AopProxyDemo { // 输出代理对象的信息 System.out.println("JDK Class = " + myService.getClass()); // 调用代理对象的方法 - System.out.println("doSomething method result = " + myService.doSomething()); + myService.doSomething(); } } diff --git a/spring-aop/spring-aop-aopProxy/src/main/java/com/xcs/spring/MyMethodInterceptor.java b/spring-aop/spring-aop-aopProxy/src/main/java/com/xcs/spring/MyMethodInterceptor.java new file mode 100644 index 0000000..801bfb5 --- /dev/null +++ b/spring-aop/spring-aop-aopProxy/src/main/java/com/xcs/spring/MyMethodInterceptor.java @@ -0,0 +1,17 @@ +package com.xcs.spring; + +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +public class MyMethodInterceptor implements MethodInterceptor { + @Override + public Object invoke(MethodInvocation invocation) throws Throwable { + // 在方法调用之前执行的逻辑 + System.out.println("Before " + invocation.getMethod().getName()); + // 调用原始方法 + Object result = invocation.proceed(); + // 在方法调用之后执行的逻辑 + System.out.println("After " + invocation.getMethod().getName()); + return result; + } +} diff --git a/spring-aop/spring-aop-aopProxy/src/main/java/com/xcs/spring/MyService.java b/spring-aop/spring-aop-aopProxy/src/main/java/com/xcs/spring/MyService.java index 0cf16d5..059151f 100644 --- a/spring-aop/spring-aop-aopProxy/src/main/java/com/xcs/spring/MyService.java +++ b/spring-aop/spring-aop-aopProxy/src/main/java/com/xcs/spring/MyService.java @@ -2,6 +2,6 @@ package com.xcs.spring; public interface MyService { - String doSomething(); + void doSomething(); } diff --git a/spring-aop/spring-aop-aopProxy/src/main/java/com/xcs/spring/MyServiceImpl.java b/spring-aop/spring-aop-aopProxy/src/main/java/com/xcs/spring/MyServiceImpl.java index 9e3938e..c0c66dd 100644 --- a/spring-aop/spring-aop-aopProxy/src/main/java/com/xcs/spring/MyServiceImpl.java +++ b/spring-aop/spring-aop-aopProxy/src/main/java/com/xcs/spring/MyServiceImpl.java @@ -3,7 +3,7 @@ package com.xcs.spring; public class MyServiceImpl implements MyService { @Override - public String doSomething() { - return "hello world"; + public void doSomething() { + System.out.println("doSomething..."); } }