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

文章目录

  • 系列文档索引
  • 五、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() {@Overridepublic Pointcut getPointcut() {return new Pointcut() {@Overridepublic ClassFilter getClassFilter() {return new ClassFilter() {@Overridepublic boolean matches(Class<?> clazz) {// 类匹配器return false;}};}@Overridepublic MethodMatcher getMethodMatcher() {// 方法匹配器return new MethodMatcher() {@Overridepublic boolean matches(Method method, Class<?> targetClass) {return false;}@Overridepublic boolean isRuntime() {return false; // 如果为true时,下面的参数matches就会生效}@Overridepublic boolean matches(Method method, Class<?> targetClass, Object... args) {return false;}};}};}@Overridepublic Advice getAdvice() {return new MyAfterAdvice();}// 没用@Overridepublic 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@NullableClass<?> getTargetClass();// true表示目标不可变,意味着会缓存Targetboolean isStatic();// 返回目标实例。在AOP框架调用AOP方法调用的“目标”之前立即调用。@NullableObject 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() {@Overridepublic Class<?> getTargetClass() {return descriptor.getDependencyType();}@Overridepublic boolean isStatic() {return false;}@Overridepublic 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;}@Overridepublic 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 或者配置了接口,就走jdkif (!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表达式 就用jdkif (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@Nullablepublic 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,默认为falseif (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));// 获取和被代理类所匹配的AdvisorCallback[] 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 aboveenhancer.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() failedthrow 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 advicetargetInterceptor,  // invoke target without considering advice, if optimizednew SerializableNoOp(),  // no override for methods mapped to thistargetDispatcher, 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  初始值 - 1Object interceptorOrInterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);// 当前interceptor是InterceptorAndDynamicMethodMatcher,则先进行匹配,匹配成功后再调用该Interceptor// 如果没有匹配则递归调用proceed()方法,调用下一个interceptorif (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.// 不匹配则执行下一个MethodInterceptorreturn 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方法进行递归// 比如MethodBeforeAdviceInterceptorreturn ((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.mzph.cn/news/827218.shtml

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

相关文章

算法导论 总结索引 | 第三部分 第十一章:散列表

1、动态集合结构&#xff0c;它至少要支持 INSERT、SEARCH 和 DELETE字典操作 散列表 是实现字典操作的 一种有效的数据结构。尽管 最坏情况下&#xff0c;散列表中 查找一个元素的时间 与链表中 查找的时间相同&#xff0c;达到了 Θ(n)。在实际应用中&#xff0c;散列表的性…

CB2-2CARD之Debian(Bookworm)安装Gnome看CCTV

CB2-2CARD之Debian&#xff08;Bookworm&#xff09;安装Gnome看CCTV 1. 源由2. 需求3. Debian系统桌面3.1 系统安装3.2 磁盘扩容3.3 系统更新3.4 Gnome安装 4. 测试4.1 CCTV网页测试4.2 系统空闲测试4.3 Firefox CPU占用率测试 5. 总结 1. 源由 近些年来&#xff0c;随着国内…

【学习笔记】Vue3源码解析:第五部分 - 实现渲染(3)

课程地址&#xff1a;【已完结】全网最详细Vue3源码解析&#xff01;&#xff08;一行行带你手写Vue3源码&#xff09; 第五部分-&#xff1a;&#xff08;对应课程的第36 - 37节&#xff09; 第36节&#xff1a;《处理proxy&#xff0c;方便取值》 1、执行组件中的 render 方…

Golang 开发实战day11 - Pass By Value

&#x1f3c6;个人专栏 &#x1f93a; leetcode &#x1f9d7; Leetcode Prime &#x1f3c7; Golang20天教程 &#x1f6b4;‍♂️ Java问题收集园地 &#x1f334; 成长感悟 欢迎大家观看&#xff0c;不执着于追求顶峰&#xff0c;只享受探索过程 Golang 开发实战day11 - 按值…

vector的底层与使用

前言&#xff1a;vector是顺序表&#xff08;本质也是数组&#xff09; 文档参考网站&#xff1a;https://legacy.cplusplus.com/reference/vector/vector/vector/ //底层代码 #include<assert.h> #include<iostream> #include<vector> #include<string&g…

第二部分-Foundation基础-学习导航

专题地址&#xff1a;MacOS一站式程序开发系列专题 第一部分&#xff1a;基础入门-学习导航 ObjectiveC-第一部分-基础入门-学习导航 第二部分&#xff1a;Foundation基础学习导航 Foundation框架-13-数据对象&#xff1a;主要讲述NSRange, NSString, NSValue, NSNull, NSD…

CFCASSL证书的网络安全解决方案

在数字化时代&#xff0c;网络信息安全的重要性不言而喻。随着电子商务、在线交易、远程办公等互联网活动的日益普及&#xff0c;确保数据传输的安全性与隐私保护成为企业和用户共同关注的焦点。在此背景下&#xff0c;CFCA SSL证书作为一种权威、高效的网络安全解决方案&#…

[LitCTF 2023]PHP是世界上最好的语言!!、 [LitCTF 2023]Vim yyds、 [羊城杯 2020]easycon

目录 [LitCTF 2023]PHP是世界上最好的语言&#xff01;&#xff01; [LitCTF 2023]Vim yyds [羊城杯 2020]easycon [LitCTF 2023]PHP是世界上最好的语言&#xff01;&#xff01; 无参&#xff0c;根据题目提示看看php能否执行——返回1执行成功 用system()函数调用、执行ls …

C++教你如何模拟实现string,如何实现string写时拷贝

文章目录 前言成员变量默认成员函数默认构造函数拷贝构造函数析构函数赋值运算符重载 容量相关函数&#xff08;Capacity&#xff09;reserve函数resize函数size函数capacity 函数clear函数 修改函数&#xff08;Modifiers&#xff09;swap函数insert函数字符插入字符串插入 ap…

基于docker搭建瀚高数据库HighGo6.0.1【图文】

基于docker搭建瀚高数据库HighGo6.0.1 拉取镜像启动验证进入容器 登录数据库查看数据库加密方式修改加密方式为sm3进入数据库修改密码重启容器 数据库验证数据库密码到期参考 docker部署 https://blog.csdn.net/weixin_44385419/article/details/127738868 拉取镜像 docker p…

【Java】变量零基础教程

目录 一、引言 二、基本组成单位 三、变量的基本原理 四、变量的基本使用步骤 五、变量快速入门 六、变量使用的注意事项 一、引言 为什么需要变量&#xff1f; ​​​​​​一个程序就是一个世界。 大家看下图&#xff0c;是我们现实中的一张生活照&#xff0c;图里有树…

spring aop介绍

Spring AOP&#xff08;面向切面编程&#xff09;是一种编程范式&#xff0c;它允许开发者将横切关注点&#xff08;cross-cutting concerns&#xff09;从业务逻辑中分离出来&#xff0c;从而提高代码的模块化。在传统的对象导向编程中&#xff0c;这些横切关注点&#xff0c;…

ic基础|时序篇:握手协议valid和ready的时序优化

大家好&#xff0c;我是数字小熊饼干&#xff0c;一个练习时长两年半的ic打工人。我在两年前通过自学跨行社招加入了IC行业。现在我打算将这两年的工作经验和当初面试时最常问的一些问题进行总结&#xff0c;并通过汇总成文章的形式进行输出&#xff0c;相信无论你是在职的还是…

Maven的常用基本命令

Maven是一个Java项目的构建和依赖管理工具&#xff0c;它有一系列命令用于项目的构建、清理、安装、部署等操作。以下是一些Maven的常用命令及其详细解释与举例&#xff1a; 1.mvn clean 功能&#xff1a;清理项目构建过程中生成的中间文件和目标目录&#xff08;target&…

HarmonyOS开发案例:【视频播放器】

介绍 基于video、swiper和slider组件&#xff0c;实现简单的视频播放器&#xff0c;可支持海报轮播、视频播放等功能。 相关概念 [video组件]&#xff1a;视频播放组件。[swiper组件]&#xff1a;滑动容器&#xff0c;提供切换子组件显示的能力。[slider组件]&#xff1a;滑…

秋招之路 面经

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

针对窗口数量多导致窗口大小显示受限制的问题,使用滚动条控制窗口

建议&#xff1a;首先观察结果展示&#xff0c;判断是否可以满足你的需求。 目录 1. 问题分析 2. 解决方案 2.1 界面设计 2.2 生成代码 2.3 源码实现 3. 结果展示 1. 问题分析 项目需要显示的窗口数量颇多&#xff0c;主界面中&#xff0c;如果一次性显示全部窗口&#x…

Web3钱包开发获取测试币-Base Sepolia(二)

Web3钱包开发获取测试币-Base Sepolia(二) ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/b0c0ac86b04a496087471388532bc54a.png) 基于上篇 Web3钱包开发获取测试币-Polygon Mumbai(一) &#xff1a;https://suwu150.blog.csdn.net/article/details/137949473 我…

MyBatis 框架学习(I)

MyBatis 框架学习(I) 文章目录 MyBatis 框架学习(I)1. 介绍2. 准备&测试3. MyBatis 注解基础操作3.1 日志输出3.2 Insert 操作3.3 Delete 操作3.4 Update 操作3.5 Select 操作 总结 1. 介绍 之前我们学习过利用JDBC操作数据库进行项目开发&#xff0c;但我们发现它操作起来…

扫描工具nmap

介绍 说到黑客&#xff0c;知识就是力量。您对目标系统或网络的了解越多&#xff0c;可用的选项就越多。因此&#xff0c;在进行任何利用尝试之前&#xff0c;必须进行适当的枚举。 假设我们获得了一个 IP&#xff08;或多个 IP 地址&#xff09;来执行安全审计。在我们做任何…