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.hqwc.cn/news/637884.html

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

相关文章

数码摄影色彩构成,数码相机色彩管理

一、资料描述 本套摄影色彩资料&#xff0c;大小58.54M&#xff0c;共有6个文件。 二、资料目录 《抽象彩色摄影集》.阿瑟.pdf 《色彩构成》.pdf 《色彩学》.星云.扫描版.pdf 《摄影色彩构成》.pdf 《数码相机色彩管理》.pdf 数码摄影进阶之4《色彩篇》.pdf 三、资料下…

随心玩玩(十五)LLM 浅玩一下RWKV模型

写在前面&#xff1a;无聊又来玩玩LLM了&#xff0c;这次玩玩RWKV&#xff0c;因为我看到hugging face上有个roleplay的模型&#xff0c;遂心动。 【烧显存注意&#xff01;】需要16G显存的样子 介绍 &#xff08;随便cv的&#xff0c;见谅&#xff0c;有空单独写一篇博客看看…

Matlab新手快速上手2(粒子群算法)

本文根据一个较为简单的粒子群算法框架详细分析粒子群算法的实现过程&#xff0c;对matlab新手友好&#xff0c;源码在文末给出。 粒子群算法简介 粒子群算法&#xff08;Particle Swarm Optimization&#xff0c;PSO&#xff09;是一种群体智能优化算法&#xff0c;灵感来源于…

websocket 请求头报错 Provisional headers are shown 的解决方法

今日简单总结 websocket 使用过程中遇到的问题&#xff0c;主要从以下三个方面来分享&#xff1a; 1、前端部分 websocket 代码 2、使用 koa.js 实现后端 websocket 服务搭建 3、和后端 java Netty 库对接时遇到连接失败问题 一、前端部分 websocket 代码 <template>…

社会工程渗透测试教程(四)

原文&#xff1a;annas-archive.org/md5/db987a87e1478b8a8617c263c631b477 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 第十三章&#xff1a;撰写报告 安德鲁梅森&#xff0c;技术总监&#xff0c;RandomStorm 有限公司 本章将介绍向客户提供的主要成果&#xf…

嵌入式物联网实战开发笔记-乐鑫ESP32开发环境ESP-IDF搭建【doc.yotill.com】

乐鑫ESP32入门到精通项目开发参考百例下载&#xff1a; 链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;4e33 3.1 ESP-IDF 简介 ESP-IDF&#xff08;Espressif IoT Development Framework&#xff09;是乐鑫&#xff08;Espressif Systems&#xff09;为 ESP 系列…

FineBi中创建自定义的图表

FineBi中增加自己的自定义图表组件,比如: 的相关笔记: 1 获取有哪些BI自定义图表组件:http://localhost:8080/webroot/decision/v5/plugin/custom/component/list?_=1713667435473[{"name": "图表DEMO_EK","chartType": "amap_demo&q…

LinkedList和链表

1.ArrayList的缺陷 ArraryList由于底层是一段连续的空间&#xff0c;所以在ArrayList任意位置插入或者删除元素时&#xff0c;就 需要将后续元素往前或者往后搬移&#xff0c;时间复杂度为O(n)&#xff0c;效率比较低&#xff0c;因此ArrayList不适合做任意位置插入和删除比较…

rmallox勒索病毒威胁网络安全:如何避免数据被锁定

尊敬的读者&#xff1a; 随着信息技术的飞速发展&#xff0c;网络空间的安全问题日益凸显。近年来&#xff0c;一种名为.rmallox的勒索病毒频繁出没&#xff0c;给广大计算机用户带来了严重的困扰。本文将对该病毒进行深入剖析&#xff0c;并探讨相应的应对策略。在面对被勒索…

十大排序算法详解-上篇:比较排序算法【python 动态图解】

作者介绍&#xff1a;10年大厂数据\经营分析经验&#xff0c;现任大厂数据部门负责人。 会一些的技术&#xff1a;数据分析、算法、SQL、大数据相关、python 欢迎加入社区&#xff1a;码上找工作 作者专栏每日更新&#xff1a; LeetCode解锁1000题: 打怪升级之旅 python数据分析…

11.接口自动化学习-Yaml学习

1.配置文件作用 配置文件项目角度&#xff1a; &#xff08;1&#xff09;现成的应用–第三方组件 mysql–数据库–my.conf tomcat–web服务器–server.xml 修改&#xff1a;连接数/端口 redis–缓存服务器–redis.conf 修改配置 jemeter–压测工具–jemeter.properties–修改…

【探讨】RocketMQ消息灰度方案-消息逻辑隔离

vivo 鲁班平台 RocketMQ 消息灰度方案 - 稀土掘金分布式- vivo鲁班RocketMQ平台的消息灰度方案MQ消息在生产环境和灰度环境隔离一般怎么实现?消息隔离的原则 中心正常消费者,可以同时消费正常的消息和特定标签的消息(自动识别);特定标签的消费者,只能消费特定标签的消息。灰…