SpringAOP从入门到源码分析大全(三)ProxyFactory源码分析

news2024/12/27 11:04:06

文章目录

  • 系列文档索引
  • 五、ProxyFactory源码分析
    • 1、案例
    • 2、认识TargetSource
      • (1)何时用到TargetSource
      • (2)@Lazy的原理
      • (3)应用TargetSource
    • 3、ProxyFactory选择cglib或jdk动态代理原理
    • 4、jdk代理获取代理方法的逻辑
      • (1)getInterceptorsAndDynamicInterceptionAdvice获取拦截器链
      • (2)包装AfterReturningAdvice、MethodBeforeAdvice为MethodInterceptor
      • (3)总结
    • 5、cglib代理获取代理方法的逻辑
      • (1)getCallbacks获取callback方法
      • (2)总结
    • 6、执行器链执行逻辑

系列文档索引

SpringAOP从入门到源码分析大全(一)熟悉动态代理
SpringAOP从入门到源码分析大全(二)熟悉ProxyFactory
SpringAOP从入门到源码分析大全(三)ProxyFactory源码分析
SpringAOP从入门到源码分析大全(四)SpringAOP的源码分析
SpringAOP从入门到源码分析大全(五)手写一个编程式AOP

五、ProxyFactory源码分析

1、案例

UserService userService = new UserService();
// spring 将cglib和jdk动态代理合二为一了,如果有接口,就会走jdk代理,如果只有类,就会走cglib代理
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(userService);
// 可以设置多个Advice,会形成代理链
proxyFactory.addAdvice(new MyBeforeAdvice());
proxyFactory.addAdvice(new MyAroundAdvice());
proxyFactory.addAdvice(new MyAfterAdvice());

proxyFactory.addAdvisor(new PointcutAdvisor() {
    @Override
    public Pointcut getPointcut() {
        return new Pointcut() {
            @Override
            public ClassFilter getClassFilter() {
                return new ClassFilter() {
                    @Override
                    public boolean matches(Class<?> clazz) {
                        // 类匹配器
                        return false;
                    }
                };
            }

            @Override
            public MethodMatcher getMethodMatcher() {
                // 方法匹配器
                return new MethodMatcher() {
                    @Override
                    public boolean matches(Method method, Class<?> targetClass) {
                        return false;
                    }

                    @Override
                    public boolean isRuntime() {
                        return false; // 如果为true时,下面的参数matches就会生效
                    }

                    @Override
                    public boolean matches(Method method, Class<?> targetClass, Object... args) {
                        return false;
                    }
                };
            }
        };
    }

    @Override
    public Advice getAdvice() {
        return new MyAfterAdvice();
    }

    // 没用
    @Override
    public boolean isPerInstance() {
        return true;
    }
});

UserService proxy = (UserService) proxyFactory.getProxy();

proxy.test();

2、认识TargetSource

(1)何时用到TargetSource

我们在调用proxyFactory.setTarget方法时,是将原始对象封装为了SingletonTargetSource。
在这里插入图片描述
SingletonTargetSource实现了TargetSource接口,相当于非常简单的一个TargetSource。

// 动态目标源可以支持池化、热插拔等。
public interface TargetSource extends TargetClassAware {

	// 返回TargetSource返回的目标类型。
	@Override
	@Nullable
	Class<?> getTargetClass();

	// true表示目标不可变,意味着会缓存Target
	boolean isStatic();

	// 返回目标实例。在AOP框架调用AOP方法调用的“目标”之前立即调用。
	@Nullable
	Object getTarget() throws Exception;

	// 释放从getTarget()方法获得的给定目标对象(如果有的话)。
	void releaseTarget(Object target) throws Exception;

}

其实,AOP代理的对象,每次调用代理对象的方法时,获取的原始对象就是从TargetSource 的getTarget方法中获取的,这就意味着具备了很强的灵活性。

(2)@Lazy的原理

@Autowired
private UserService userService;

在属性注入时,使用@Lazy注解,并不会初始化Bean,而是将代理对象赋值给了属性。

我们看一下@Lazy属性赋值的源码:

// org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver#buildLazyResolutionProxy
protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final @Nullable String beanName) {
	BeanFactory beanFactory = getBeanFactory();
	Assert.state(beanFactory instanceof DefaultListableBeanFactory,
			"BeanFactory needs to be a DefaultListableBeanFactory");
	final DefaultListableBeanFactory dlbf = (DefaultListableBeanFactory) beanFactory;

	TargetSource ts = new TargetSource() {
		@Override
		public Class<?> getTargetClass() {
			return descriptor.getDependencyType();
		}
		@Override
		public boolean isStatic() {
			return false;
		}
		@Override
		public Object getTarget() {
			Set<String> autowiredBeanNames = (beanName != null ? new LinkedHashSet<>(1) : null);
			Object target = dlbf.doResolveDependency(descriptor, beanName, autowiredBeanNames, null);
			if (target == null) {
				Class<?> type = getTargetClass();
				if (Map.class == type) {
					return Collections.emptyMap();
				}
				else if (List.class == type) {
					return Collections.emptyList();
				}
				else if (Set.class == type || Collection.class == type) {
					return Collections.emptySet();
				}
				throw new NoSuchBeanDefinitionException(descriptor.getResolvableType(),
						"Optional dependency not present for lazy injection point");
			}
			if (autowiredBeanNames != null) {
				for (String autowiredBeanName : autowiredBeanNames) {
					if (dlbf.containsBean(autowiredBeanName)) {
						dlbf.registerDependentBean(autowiredBeanName, beanName);
					}
				}
			}
			return target;
		}
		@Override
		public void releaseTarget(Object target) {
		}
	};

	ProxyFactory pf = new ProxyFactory();
	pf.setTargetSource(ts);
	Class<?> dependencyType = descriptor.getDependencyType();
	if (dependencyType.isInterface()) {
		pf.addInterface(dependencyType);
	}
	return pf.getProxy(dlbf.getBeanClassLoader());
}

上面的源码可以看出,就是将属性赋值了一个代理对象,而TargetSource 的getTarget方法,就是从容器中获取目标对象的Bean进行返回。很巧妙的实现了懒加载。

(3)应用TargetSource

实际上我们日常开发中,很少会用到TargetSource。

我们也可以使用TargetSource实现懒加载、池化(每次获取Target都是从池子里获取)、热插拔(每次获取Target都是重新获取)。

3、ProxyFactory选择cglib或jdk动态代理原理

ProxyFactory在生成代理对象之前需要决定到底是使用JDK动态代理还是CGLIB技术:

// org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
	// 是GraalVM 就直接用jdk代理
	// Optimize == true或者isProxyTargetClass == true 或者配置了接口,就走jdk
	if (!NativeDetector.inNativeImage() &&
			(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
		Class<?> targetClass = config.getTargetClass();
		if (targetClass == null) {
			throw new AopConfigException("TargetSource cannot determine target class: " +
					"Either an interface or a target is required for proxy creation.");
		}
		// 被代理的类是接口 或 被代理的类已经是jdk代理类了 或 lambda表达式 就用jdk
		if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {
			return new JdkDynamicAopProxy(config);
		}
		return new ObjenesisCglibAopProxy(config);
	}
	else {
		return new JdkDynamicAopProxy(config);
	}
}

然后获取代理类的方法,就是jdk和cglib代理的逻辑。

4、jdk代理获取代理方法的逻辑

JdkDynamicAopProxy实现了InvocationHandler方法,JdkDynamicAopProxy调用其getProxy方法,执行目标方法就会执行JdkDynamicAopProxy的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 {
			// 如果接口中没有定义equals()方法,那么直接调用,不走代理
			if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
				// The target does not implement the equals(Object) method itself.
				return equals(args[0]);
			}
			else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
				// The target does not implement the hashCode() method itself.
				return hashCode();
			}
			else if (method.getDeclaringClass() == DecoratingProxy.class) {
				// There is only getDecoratedClass() declared -> dispatch to proxy config.
				// 得到代理对象的类型,而不是所实现的接口
				return AopProxyUtils.ultimateTargetClass(this.advised);
			}
			else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
					method.getDeclaringClass().isAssignableFrom(Advised.class)) {
				// Service invocations on ProxyConfig with the proxy config...
				// 也是直接调用Advised接口中的方法,不走代理逻辑
				// 其实就是利用代理对象获取ProxyFactory中的信息
				return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
			}

			Object retVal;
			// 如果ProxyFactory的exposeProxy为true,则将代理对象设置到currentProxy这个ThreadLocal中去
			// 如果使用@EnableAspectJAutoProxy注解,需要手动将该参数设置为true,默认为false
			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<?> targetClass = (target != null ? target.getClass() : null);

			// Get the interception chain for this method.
			// 代理对象在执行某个方法时,根据方法筛选出匹配的Advisor,并适配成Interceptor 代理链
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

			// Check whether we have any advice. If we don't, we can fall back 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.
				// 如果没有Advice,则直接调用对应方法
				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);
			}
		}
	}

(1)getInterceptorsAndDynamicInterceptionAdvice获取拦截器链

// org.springframework.aop.framework.AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
	// 代理对象在执行某个方法时,会根据当前ProxyFactory中所设置的Advisor根据当前method再次进行过滤
	MethodCacheKey cacheKey = new MethodCacheKey(method);
	// 注意这个List,表示的就是Advice,有缓存。
	List<Object> cached = this.methodCache.get(cacheKey);
	if (cached == null) {
		cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
				this, method, targetClass);
		this.methodCache.put(cacheKey, cached);
	}
	return cached;
}
// org.springframework.aop.framework.DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
		Advised config, Method method, @Nullable Class<?> targetClass) {

	// This is somewhat tricky... We have to process introductions first,
	// but we need to preserve order in the ultimate list.
	AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
	// 从ProxyFactory中拿到所设置的Advice,(添加时被封装成了DefaultPointcutAdvisor)
	// 添加的时候会控制顺序
	Advisor[] advisors = config.getAdvisors();
	List<Object> interceptorList = new ArrayList<>(advisors.length);
	Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
	Boolean hasIntroductions = null;

	for (Advisor advisor : advisors) {
		if (advisor instanceof PointcutAdvisor) {
			// Add it conditionally.
			PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
			// 先匹配类
			if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
				MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
				boolean match;
				// 再匹配方法
				if (mm instanceof IntroductionAwareMethodMatcher) {
					if (hasIntroductions == null) {
						hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
					}
					match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
				}
				else {
					match = mm.matches(method, actualClass);
				}
				if (match) {
					// 如果匹配,则将Advisor封装成Interceptor,当前Advisor中的Advice可能既是MethodBeforeAdvice也是ThrowingAdvice,除了around的都需要包装
					MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
					if (mm.isRuntime()) { // true 需要包装Interceptor,会将参数传过来进行判断
						// Creating a new object instance in the getInterceptors() method
						// isn't a problem as we normally cache created chains.
						for (MethodInterceptor interceptor : interceptors) {
							interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
						}
					}
					else {
						interceptorList.addAll(Arrays.asList(interceptors));
					}
				}
				// 最终,interceptorList中存储的是当前正在执行的Method所匹配的MethodInterceptor,可能是动态的,也可能是非动态的。
				// 找到Method所匹配的MethodInterceptor后,就会开始调用这些MethodInterceptor,如果是动态的,会额外进行方法参数的匹配判断
			}
		}
		else if (advisor instanceof IntroductionAdvisor) {
			IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
			if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
				Interceptor[] interceptors = registry.getInterceptors(advisor);
				interceptorList.addAll(Arrays.asList(interceptors));
			}
		}
		else {
			Interceptor[] interceptors = registry.getInterceptors(advisor);
			interceptorList.addAll(Arrays.asList(interceptors));
		}
	}

	return interceptorList;
}

(2)包装AfterReturningAdvice、MethodBeforeAdvice为MethodInterceptor

包装的MethodInterceptor和around的效果是一样的。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

ThrowsAdviceInterceptor:复杂一些,会将异常类型匹配出来

在这里插入图片描述

在这里插入图片描述

(3)总结

在构造JdkDynamicAopProxy对象时,会先拿到被代理对象自己所实现的接口,并且额外的增加SpringProxy、Advised、DecoratingProxy三个接口,组合成一个Class[],并赋值给proxiedInterfaces属性

并且检查这些接口中是否定义了equals()、hashcode()方法

执行Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this),得到代理对象,JdkDynamicAopProxy作为InvocationHandler,代理对象在执行某个方法时,会进入到JdkDynamicAopProxy的**invoke()**方法中

5、cglib代理获取代理方法的逻辑

CglibAopProxy的getProxy方法逻辑:

// org.springframework.aop.framework.CglibAopProxy#getProxy(java.lang.ClassLoader)
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
	if (logger.isTraceEnabled()) {
		logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
	}

	try {
		// 被代理的类
		Class<?> rootClass = this.advised.getTargetClass();
		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);
			}
		}

		// Validate the class, writing log messages as necessary.
		validateClassIfNecessary(proxySuperClass, classLoader);

		// Configure CGLIB Enhancer...
		Enhancer enhancer = createEnhancer();
		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));
		// 获取和被代理类所匹配的Advisor
		Callback[] callbacks = getCallbacks(rootClass);
		Class<?>[] types = new Class<?>[callbacks.length];
		for (int x = 0; x < types.length; x++) {
			types[x] = callbacks[x].getClass();
		}
		// fixedInterceptorMap only populated at this point, after getCallbacks call above
		enhancer.setCallbackFilter(new ProxyCallbackFilter(
				this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
		enhancer.setCallbackTypes(types);

		// Generate the proxy class and create a proxy instance.
		return createProxyClassAndInstance(enhancer, callbacks);
	}
	catch (CodeGenerationException | IllegalArgumentException ex) {
		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) {
		// TargetSource.getTarget() failed
		throw new AopConfigException("Unexpected AOP exception", ex);
	}
}

(1)getCallbacks获取callback方法

// org.springframework.aop.framework.CglibAopProxy#getCallbacks
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
	// Parameters used for optimization choices...
	boolean isFrozen = this.advised.isFrozen();
	boolean exposeProxy = this.advised.isExposeProxy();
	boolean isStatic = this.advised.getTargetSource().isStatic();

	// Choose an "aop" interceptor (used for AOP calls).
	// 重要
	Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

	// Choose a "straight to target" interceptor. (used for calls that are
	// unadvised but can return this). May be required to expose the proxy.
	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()));
	}

	// Choose a "direct to target" dispatcher (used for
	// unadvised calls to static targets that cannot return this).
	Callback targetDispatcher = (isStatic ?
			new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp());

	Callback[] mainCallbacks = new Callback[] {
			aopInterceptor,  // for normal advice
			targetInterceptor,  // invoke target without considering advice, if optimized
			new SerializableNoOp(),  // no override for methods mapped to this
			targetDispatcher, this.advisedDispatcher,
			new EqualsInterceptor(this.advised),
			new HashCodeInterceptor(this.advised)
	};

	Callback[] callbacks;

	// If the target is a static one and the advice chain is frozen,
	// then we can make some optimizations by sending the AOP calls
	// direct to the target using the fixed chain for that method.
	if (isStatic && isFrozen) {
		Method[] methods = rootClass.getMethods();
		Callback[] fixedCallbacks = new Callback[methods.length];
		this.fixedInterceptorMap = CollectionUtils.newHashMap(methods.length);

		// TODO: small memory optimization here (can skip creation for methods with no advice)
		for (int x = 0; x < methods.length; x++) {
			Method method = methods[x];
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass);
			fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
					chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
			this.fixedInterceptorMap.put(method, x);
		}

		// Now copy both the callbacks from mainCallbacks
		// and fixedCallbacks into the callbacks array.
		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
@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) {
			// 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<?> targetClass = (target != null ? target.getClass() : null);
		List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
		Object retVal;
		// Check whether we only have one InvokerInterceptor: that is,
		// no real advice, but just reflective invocation of the target.
		if (chain.isEmpty() && CglibMethodInvocation.isMethodProxyCompatible(method)) {
			// 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 = invokeMethod(target, method, argsToUse, methodProxy);
		}
		else {
			// We need to create a method invocation...
			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) {
			// Restore old proxy.
			AopContext.setCurrentProxy(oldProxy);
		}
	}
}

(2)总结

创建Enhancer对象

设置Enhancer的superClass为通过ProxyFactory.setTarget()所设置的对象的类

设置Enhancer的interfaces为通过ProxyFactory.addInterface()所添加的接口,以及SpringProxy、Advised、DecoratingProxy接口

设置Enhancer的Callbacks为DynamicAdvisedInterceptor

最后创建一个代理对象,代理对象在执行某个方法时,会进入到DynamicAdvisedInterceptor的intercept()方法中

6、执行器链执行逻辑

// org.springframework.aop.framework.ReflectiveMethodInvocation#proceed
@Override
@Nullable
public Object proceed() throws Throwable {
	// We start with an index of -1 and increment early.
	// 当调用完了最后一个interceptor后会就执行被代理方法
	if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
		// 调用目标方法
		return invokeJoinpoint();
	}

	// currentInterceptorIndex  初始值 - 1
	Object interceptorOrInterceptionAdvice =
			this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

	// 当前interceptor是InterceptorAndDynamicMethodMatcher,则先进行匹配,匹配成功后再调用该Interceptor
	// 如果没有匹配则递归调用proceed()方法,调用下一个interceptor
	if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
		// Evaluate dynamic method matcher here: static part will already have
		// been evaluated and found to match.
		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 {
			// Dynamic matching failed.
			// Skip this interceptor and invoke the next in the chain.
			// 不匹配则执行下一个MethodInterceptor
			return proceed();
		}
	}
	else {
		// It's an interceptor, so we just invoke it: The pointcut will have
		// been evaluated statically before this object was constructed.
		// 直接调用MethodInterceptor,传入this,在内部会再次调用proceed方法进行递归
		// 比如MethodBeforeAdviceInterceptor
		return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
	}
}

在使用ProxyFactory创建代理对象之前,需要往ProxyFactory先添加Advisor

代理对象在执行某个方法时,会把ProxyFactory中的Advisor拿出来和当前正在执行的方法进行匹配筛选

把和方法所匹配的Advisor适配成MethodInterceptor

把和当前方法匹配的MethodInterceptor链,以及被代理对象、代理对象、代理类、当前Method对象、方法参数封装为MethodInvocation对象

调用MethodInvocation的proceed()方法,开始执行各个MethodInterceptor以及被代理对象的对应方法

按顺序调用每个MethodInterceptor的invoke()方法,并且会把MethodInvocation对象传入invoke()方法

直到执行完最后一个MethodInterceptor了,就会调用invokeJoinpoint()方法,从而执行被代理对象的当前方法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1615893.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

内存泄漏详解

一、什么是内存泄漏&#xff1f;二、内存泄漏的原因三、内存泄漏的影响四、如何检测和解决内存泄漏&#xff1f;五、总结 一、什么是内存泄漏&#xff1f; 内存泄漏指的是程序中已分配的内存没有被正确释放&#xff0c;导致这部分内存无法被再次利用&#xff0c;最终导致内存资…

【Java框架】SpringBoot(一)基本入门

目录 SpringBoot介绍Spring Boot的诞生SpringBoot特点Spring和Spring Boot的关系Spring Boot的优点和缺点Spring Boot优点Spring Boot缺点 快速创建Spring Boot项目 IDEA创建SpringBoot工程1.打开IDEA&#xff0c;选择Spring Initlializr2.选择SpringBoot版本和初始化依赖3.更改…

病理验证mIF和TMA路线(自学)

目录 技术 使用配对病理切片 mIF验证 单基因使用TMA验证 技术 多重荧光免疫组化技术 (Multiplex immunohistochemical&#xff0c;mIHC) 也称作酪氨酸信号放大 (Tyramide dignal amplification&#xff0c;TSA) 技术&#xff0c;是一类利用辣根过氧化酶 (Horseradish Pero…

(一)Java EE企业级应用开发实战之Servlet教程——JDK安装

首先打开清华大学开源软件镜像站&#xff0c;清华大学开源镜像网站地址为&#xff1a; https://mirrors.tuna.tsinghua.edu.cn/ 打开该地址后的界面显示如下图所示 找到8版本对应的SDK安装包&#xff0c;我现在用的开发机器是Windows&#xff0c;所以我找的是Windows对应的版本…

Spring AOP (一)

本篇主要介绍Spring AOP的基础概念和入门使用 一、AOP的基本概念 AOP是一种面向切面编程的思想&#xff0c;它与IOC并称为Spring 的两大核心思想。什么是面向切面编程呢&#xff0c;具体来说就是对一类事情进行集中统一处理。这听起来像不像前面篇章中所介绍的统一功能处理&am…

Vue2 移动端(H5)项目封装弹窗组件

前言 因vant-ui的dialog组件没有自定义footer插槽 效果 参数配置 1、代码示例&#xff1a; <t-dialog :visible.sync"show" :title"title" submit"submit"></t-dialog>2、配置参数&#xff08;t-dialog Attributes&#xff09; 参…

JAVA基础之垃圾收集器

一 JVM垃圾收集 分代收集思想 当前虚拟机的垃圾收集一般采用分代收集算法&#xff0c;这种算法本身没有创新性&#xff0c;只是根据对象存活周期的不同将内存分为几块。一般将java堆内存分为新生代和老年代&#xff0c;这样我们就可以根据不同年龄到的特点选择不同的垃圾收集…

自动驾驶控制算法

本文内容来源是B站——忠厚老实的老王&#xff0c;侵删。 三个坐标系和一些有关的物理量 使用 frenet坐标系可以实现将车辆纵向控制和横向控制解耦&#xff0c;将其分开控制。使用右手系来进行学习。 一些有关物理量的基本概念&#xff1a; 运动学方程 建立微分方程 主要是弄…

Agent 智能体食用指南

Agent 智能体食用指南 三年前都在 ALL in AI&#xff0c;一年前都在 ALL in LLM&#xff0c;现在都在 ALL in AgentAutoGEN分析MetaGPT 分析RAG 分析MOE 多专家分析 三年前都在 ALL in AI&#xff0c;一年前都在 ALL in LLM&#xff0c;现在都在 ALL in Agent 科技圈焦点&…

智己汽车数据驱动中心PMO高级经理张晶女士受邀为第十三届中国PMO大会演讲嘉宾

全国PMO专业人士年度盛会 智己汽车科技有限公司数据驱动中心PMO高级经理张晶女士受邀为PMO评论主办的2024第十三届中国PMO大会演讲嘉宾&#xff0c;演讲议题为“规模化敏捷落地实践”。大会将于5月25-26日在北京举办&#xff0c;敬请关注&#xff01; 议题简要&#xff1a; 2…

Spring Bean依赖注入-Spring入门(二)

1、SpringBean概述 在Spring中&#xff0c;一切Java对象都被视为Bean&#xff0c;用于实现某个具体功能。 Bean的依赖关系注入的过程&#xff0c;也称为Bean的装配过程。 Bean的装配方式有3种&#xff1a; XML配置文件注解Java类 Spring中常用的两种装配方式分别是基于XML的…

秋招之路 面经

这里参考一位很厉害的前辈所分享的他的嵌入式软件工程师秋招之路&#xff0c;自己详细的读了一下他的经历以及他的分享的秋招面试和项目经验的总结。 我的嵌入式软件工程师秋招之路&#xff08;文末送福利&#xff09;_嵌入式软件工程师 刷leetcode-CSDN博客 如何在面试中介绍…

UA时间控件,选择时分的控件

方式一&#xff1a; <sit-property sit-widget"sit-time-picker"sit-value"vm.StartTime"sit-format"HH:mm"sit-validation"{required: true}"sit-read-only"false">开始时间:</sit-property> 方式二&#xff…

go-cqhttp 机器人使用教程

API | go-cqhttp 帮助中心 参考 | go-cqhttp 帮助中心 机器人下载 发送消息 http://127.0.0.1:5700/send_msg?message_typeprivate&user_id911412667&message你好呀 检查端口是否打开 netstat -ano | findstr :5701 发送的请求 软件的dopost的解析 Overridepro…

【MySQL】Linux环境下MySQL基本操作

目录 一、登录进入MySQL 二、MySQL数据库的查看、创建、删除、重命名、拷贝操作 三、数据库下表的创建、删除、查看、修改&#xff08;增加、删除、更新字段/列&#xff0c;修改字段/列名&#xff09; 四、表中数据的插入、删除、查找、更新 一、登录进入MySQL mysql -u u…

【小浩算法cpp题解】判断环形链表

目录 前言我的思路思路一 &#xff08;哈希表记录链表的访问&#xff09;&#xff1a;思路二 &#xff08;双指针&#xff0c;快指针在前&#xff0c;慢指针在后&#xff09;&#xff1a; 我的代码运行结果 前言 前几天我写的代码&#xff0c;都是把所有的内容写在main函数里&…

国产生骨肉冻干品控好不好?热榜TOP5生骨肉冻干分享

对于新手养猫人来说&#xff0c;进口生骨肉冻干的高价常常让人疑惑&#xff0c;为何它能在养猫达人中赢得如此高的声誉&#xff1f;与国产生骨肉冻干相比&#xff0c;进口产品的价格高出数倍&#xff0c;那么这高昂的价格是否代表了其独特的价值&#xff0c;还是只是一个消费陷…

Ghost Buster Pro for Mac:强大的系统优化工具

Ghost Buster Pro for Mac是一款功能强大的系统优化工具&#xff0c;专为Mac用户设计&#xff0c;旨在提供全方位的系统清理、优化和维护服务。 Ghost Buster Pro for Mac v3.2.5激活版下载 这款软件拥有出色的垃圾清理能力&#xff0c;能够深度扫描并清除Mac上的无效目录、文件…

小白看完这篇文章也能踏进网安大门,成为网络安全工程师

前言 在当前的互联网环境下&#xff0c;不少人感受到了职场的寒冬与996工作制的压力。然而&#xff0c;无论环境如何变化&#xff0c;掌握实用的技术始终是保障职业稳定和发展的关键。特别是在网络安全这一领域&#xff0c;技术人才需求量大且持续增长。今天&#xff0c;我们将…

出海企业必备:Zoho Desk打造高效海外工单管理体系!

出海工单系统和常见的工单系统相比有什么不同呢&#xff1f;工单系统主要事帮助售前或者售后人员记录、处理、跟踪客户需求&#xff0c;不仅有利于企业内部管理的规范化&#xff0c;还能够有效提高客户服务质量。 工单系统可以帮助出海企业搭建统一的订单管理、售后服务、甚至…