JdkDynamicAopProxy学习

简介

JdkDynamicAopProxy#invoke 是 Spring AOP(面向切面编程)框架中用于动态代理的核心方法之一。这个方法是在使用 JDK 动态代理时,通过 JdkDynamicAopProxy 类创建的代理对象上调用目标方法时,被自动调用的。以下是该方法的解析:

方法签名
首先,我们先看一下 invoke 方法的签名:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
  • proxy:被代理的对象,也就是 JDK 动态代理生成的代理实例。
  • method:被调用的方法,即代理对象上被调用的方法。
  • args:方法的参数列表。

方法功能
invoke 方法的主要功能是:

  • 确定是否应该拦截:检查调用的方法是否匹配任何一个通知(advice)的切点(pointcut)。如果是,则进行拦截;否则,直接调用目标方法。
  • 创建拦截链:如果方法需要被拦截,根据配置创建一个拦截链(Interceptor Chain),链中的每个环节都是一个通知(Advice)。
  • 执行拦截链:按照配置的顺序执行拦截链,通常包括前置通知(Before Advice)、目标方法调用、后置通知(After Advice)、异常通知(Throws Advice)等。
  • 返回结果或抛出异常:最后,返回目标方法的结果或抛出异常。

方法流程
invoke 方法的大致流程如下:

  • 获取 AOP 配置:从代理对象中获取 AOP 配置信息,包括目标对象、通知、切点等。
  • 匹配切点:检查当前调用的方法是否匹配任何切点。如果不匹配,则直接调用目标方法并返回结果。
  • 创建拦截器链:如果方法需要被拦截,则根据配置创建一个拦截器链。每个拦截器通常包含前置逻辑、对目标方法的调用、后置逻辑以及异常处理逻辑。
  • 执行拦截器链:按照配置的顺序,依次执行拦截器链中的拦截器。在拦截器链的执行过程中,可能会修改方法参数、改变调用流程、处理异常等。
  • 调用目标方法:在拦截器链的适当位置,调用实际的目标方法。
  • 返回结果:将目标方法的返回值传递给后续的拦截器,并最终返回给调用者。
  • 处理异常:如果在执行过程中发生异常,则根据配置在拦截器链中处理异常,并可能抛出给调用者。

注意事项

  • JDK 动态代理要求目标对象必须实现至少一个接口。如果没有实现任何接口,则不能使用 JDK 动态代理,而应使用 CGLIB 或其他代理技术。
  • invoke 方法是代理对象上所有方法调用的入口点,因此它的性能对代理对象的性能至关重要。
  • 在执行拦截器链时,需要特别注意线程安全和并发控制,避免潜在的竞态条件。

源码

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {

	/** use serialVersionUID from Spring 1.2 for interoperability. */
	private static final long serialVersionUID = 5531744639992436476L;


	/*
	 * NOTE: We could avoid the code duplication between this class and the CGLIB
	 * proxies by refactoring "invoke" into a template method. However, this approach
	 * adds at least 10% performance overhead versus a copy-paste solution, so we sacrifice
	 * elegance for performance. (We have a good test suite to ensure that the different
	 * proxies behave the same :-)
	 * This way, we can also more easily take advantage of minor optimizations in each class.
	 */

	/** We use a static Log to avoid serialization issues. */
	private static final Log logger = LogFactory.getLog(JdkDynamicAopProxy.class);

	/** Config used to configure this proxy. */
	private final AdvisedSupport advised;

	/**
	 * Is the {@link #equals} method defined on the proxied interfaces?
	 */
	private boolean equalsDefined;

	/**
	 * Is the {@link #hashCode} method defined on the proxied interfaces?
	 */
	private boolean hashCodeDefined;


	/**
	 * Construct a new JdkDynamicAopProxy for the given AOP configuration.
	 * @param config the AOP configuration as AdvisedSupport object
	 * @throws AopConfigException if the config is invalid. We try to throw an informative
	 * exception in this case, rather than let a mysterious failure happen later.
	 */
	public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
		Assert.notNull(config, "AdvisedSupport must not be null");
		if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
			throw new AopConfigException("No advisors and no TargetSource specified");
		}
		this.advised = config;
	}


	@Override
	public Object getProxy() {
		return getProxy(ClassUtils.getDefaultClassLoader());
	}

	@Override
	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);
	}

	/**
	 * Finds any {@link #equals} or {@link #hashCode} method that may be defined
	 * on the supplied set of interfaces.
	 * @param proxiedInterfaces the interfaces to introspect
	 */
	//判断代理接口中是否自定义了equals和hashCode方法
	private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) {
		for (Class<?> proxiedInterface : proxiedInterfaces) {
			Method[] methods = proxiedInterface.getDeclaredMethods();
			for (Method method : methods) {
				if (AopUtils.isEqualsMethod(method)) {
					this.equalsDefined = true;
				}
				if (AopUtils.isHashCodeMethod(method)) {
					this.hashCodeDefined = true;
				}
				if (this.equalsDefined && this.hashCodeDefined) {
					return;
				}
			}
		}
	}


	/**
	 * Implementation of {@code InvocationHandler.invoke}.
	 * 

Callers will see exactly the exception thrown by the target, * unless a hook method throws an exception. */ @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 { //判断是Object中的equals方法 if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { // The target does not implement the equals(Object) method itself. return equals(args[0]); } //判断是Object中hashCode else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { // The target does not implement the hashCode() method itself. return hashCode(); } //判断是class 是DecoratingProxy.class else if (method.getDeclaringClass() == DecoratingProxy.class) { // There is only getDecoratedClass() declared -> dispatch to proxy config. //需要获取真正被代理的class return AopProxyUtils.ultimateTargetClass(this.advised); } //使用特定的代理配置(即ProxyConfig),在代理服务器上执行服务调用。 else if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) { // Service invocations on ProxyConfig with the proxy config... return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); } Object retVal; if (this.advised.exposeProxy) { // Make invocation available if necessary. oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } // Get as late as possible to minimize the time we "own" the target, // in case it comes from a pool. //获取被代理对象本身 target = targetSource.getTarget(); //获取被代理对象的Class Class<?> targetClass = (target != null ? target.getClass() : null); // Get the interception chain for this method. //获取执行链(各种通知方法) List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); // Check whether we have any advice. If we don't, we can fallback on direct // reflective invocation of the target, and avoid creating a MethodInvocation. if (chain.isEmpty()) {//如果执行链为空 则直接执行被代理对象的方法 // We can skip creating a MethodInvocation: just invoke the target directly // Note that the final invoker must be an InvokerInterceptor so we know it does // nothing but a reflective operation on the target, and no hot swapping or fancy proxying. Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } else { // We need to create a method invocation... //如果不为空 则按照执行链的逻辑执行 MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // Proceed to the joinpoint through the interceptor chain. retVal = invocation.proceed(); } // Massage return value if necessary. //获取执行的返回值类型 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); } } } /** * Equality means interfaces, advisors and TargetSource are equal. *

The compared object may be a JdkDynamicAopProxy instance itself * or a dynamic proxy wrapping a JdkDynamicAopProxy instance. */ @Override public boolean equals(@Nullable Object other) { if (other == this) { return true; } if (other == null) { return false; } JdkDynamicAopProxy otherProxy; if (other instanceof JdkDynamicAopProxy) { otherProxy = (JdkDynamicAopProxy) other; } else if (Proxy.isProxyClass(other.getClass())) { InvocationHandler ih = Proxy.getInvocationHandler(other); if (!(ih instanceof JdkDynamicAopProxy)) { return false; } otherProxy = (JdkDynamicAopProxy) ih; } else { // Not a valid comparison... return false; } // If we get here, otherProxy is the other AopProxy. return AopProxyUtils.equalsInProxy(this.advised, otherProxy.advised); } /** * Proxy uses the hash code of the TargetSource. */ @Override public int hashCode() { return JdkDynamicAopProxy.class.hashCode() * 13 + this.advised.getTargetSource().hashCode(); } }

总结

JdkDynamicAopProxy#invoke 方法是 Spring AOP 中 JDK 动态代理实现的核心,它负责根据 AOP 配置动态拦截方法调用,并执行相应的通知逻辑。通过这个方法,Spring AOP 能够在不修改原有代码的情况下,增强对象的行为,实现诸如日志记录、事务管理、安全控制等横切关注点。

你可能感兴趣的:(Spring,学习,java,spring)