网站顶部布局上饶做网站最好的公司

web/2025/9/27 19:19:38/文章来源:
网站顶部布局,上饶做网站最好的公司,深圳宝安西乡网站建设,制作网页需要什么技术文章目录 系列文档索引五、ProxyFactory源码分析1、案例2、认识TargetSource#xff08;1#xff09;何时用到TargetSource#xff08;2#xff09;Lazy的原理#xff08;3#xff09;应用TargetSource 3、ProxyFactory选择cglib或jdk动态代理原理4、jdk代理获取代理方法… 文章目录 系列文档索引五、ProxyFactory源码分析1、案例2、认识TargetSource1何时用到TargetSource2Lazy的原理3应用TargetSource 3、ProxyFactory选择cglib或jdk动态代理原理4、jdk代理获取代理方法的逻辑1getInterceptorsAndDynamicInterceptionAdvice获取拦截器链2包装AfterReturningAdvice、MethodBeforeAdvice为MethodInterceptor3总结 5、cglib代理获取代理方法的逻辑1getCallbacks获取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返回的目标类型。OverrideNullableClass? getTargetClass();// true表示目标不可变意味着会缓存Targetboolean isStatic();// 返回目标实例。在AOP框架调用AOP方法调用的“目标”之前立即调用。NullableObject getTarget() throws Exception;// 释放从getTarget()方法获得的给定目标对象(如果有的话)。void releaseTarget(Object target) throws Exception;} 其实AOP代理的对象每次调用代理对象的方法时获取的原始对象就是从TargetSource 的getTarget方法中获取的这就意味着具备了很强的灵活性。 2Lazy的原理 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() {SetString 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方法 OverrideNullablepublic 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 代理链ListObject chain this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);// Check whether we have any advice. If we dont, 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 cant 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);}}}1getInterceptorsAndDynamicInterceptionAdvice获取拦截器链 // org.springframework.aop.framework.AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice public ListObject getInterceptorsAndDynamicInterceptionAdvice(Method method, Nullable Class? targetClass) {// 代理对象在执行某个方法时会根据当前ProxyFactory中所设置的Advisor根据当前method再次进行过滤MethodCacheKey cacheKey new MethodCacheKey(method);// 注意这个List表示的就是Advice有缓存。ListObject 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 ListObject 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();ListObject 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// isnt 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);} }1getCallbacks获取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];ListObject 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);ListObject 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 {// Its 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/web/82928.shtml

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

相关文章

顺德网站建设要多少钱seo网站营销公司

一、五大数据类型 String类型、List类型、Set类型、ZSet类型、hash类型。 二、String类型 2.1、内存储存模型 2.2、常用操作命令 三、List类型 3.1、概述 list列表,相当于Java中的list集合。特点:元素有序 且 可以重复。 3.2、内存存储模型 3.3、常用…

成都网站建设公司电话厂房外墙设计效果图

项目中有段代码逻辑是个双重for循环,发现数据量大的时候,直接导致数据接口响应超时,这里记录下不断优化的过程,算是抛砖引玉吧~ Talk is cheap,show me your code! 双重for循环优化 1、数据准备2、原始双重for循环3、…

网站建设需要的准备seo有哪些作用

PathVariable是spring3.0的一个新功能:接收请求路径中占位符的值 语法: PathVariable("xxx") 通过 PathVariable 可以将URL中占位符参数{xxx}绑定到处理器类的方法形参中PathVariable(“xxx“) RequestMapping(value”user/{id}/{name}”) 请…

网站建设 服饰鞋帽wordpress 表单管理

目录 一、mybatis核心对象 (1)SqlSession对象直接操作数据库 (2)SqlSession对象通过代理对象操作数据库 二、mybatis工作流程 一、mybatis核心对象 (1)SqlSessionFactoryBuilder SqlSession工厂构建者对…

网站运营目的化工企业网站模板

链接:https://www.nowcoder.com/acm/contest/157/E来源:牛客网 有一只可爱的老青蛙,在路的另一端发现了一个黑的东西,想过去一探究竟。于是便开始踏上了旅途 一直这个小路上有很多的隧道,从隧道的a进入,会从…

深圳福田建网站个人网站做导购可以吗

Linux高性能服务器编程 本文是读书笔记,如有侵权,请联系删除。 参考 Linux高性能服务器编程源码: https://github.com/raichen/LinuxServerCodes 豆瓣: Linux高性能服务器编程 文章目录 Linux高性能服务器编程第14章 多线程编程14.1 Linux线程概述14…

做标书有什么好的网站吗自学学网页设计

过犹不及——《论语先进》 大学考试时,有些老师允许带备cheet sheet(忘纸条),上面记着关键公式和定义,帮助我们快速作答提高分数。传统的检索增强生成(RAG)方法也类似,试图找出精准的知识片段来辅助大语言模型(LLM)。 但这种方法其实有问题…

做网站的多少钱seo排名优化

lsof(List Open Files) 用于查看你进程开打的文件,打开文件的进程,进程打开的端口(TCP、UDP),找回/恢复删除的文件。是十分方便的系统监视工具,因为lsof命令需要访问核心内存和各种文件,所以需要…

三星网站建设内容做手机网站用什么程序好

在机器人的控制中&#xff0c;坐标系统是非常重要的&#xff0c;在ROS使用tf软件库进行坐标转换。 相关链接&#xff1a;http://www.ros.org/wiki/tf/Tutorials#Learning_tf 一、tf简介 我们通过一个小小的实例来介绍tf的作用。 1、安装turtle包 <span>$ rosdep instal…

漳州建设银行网站seo人才招聘

文章目录 什么是AIGC技术&#xff1f;为何AIGC技术如此火热&#xff1f;1. 提高效率与创造力的完美结合2. 拓展应用领域&#xff0c;创造商业价值3. 推动技术创新和发展 AIGC技术案例解析1. 艺术创作&#xff1a;生成独特的艺术作品2. 内容创作&#xff1a;实时生成各类内容3. …

网站建设 500强建站网站建设费属于业务宣传费吗

团队绩效考核 基于各种客观问题本次绩效考核采用和第一次冲刺不一样的标准&#xff0c;根据团队贡献事实打分如下 组员打分&#xff1a; 郭良 &#xff08;9.0&#xff09; 赵承龙 &#xff08;5.5&#xff09; &#xff08;根据组内之前定下的打分细则和本期冲刺过程的事实…

电商食品网站建设江都建设网站

图2-12所示是电源滤波电路中的高频滤波电路。电路中&#xff0c;一个容量很大的电解电容C1(2200F)与一个容量很小的电容C2(0.01F)并联&#xff0c;C2是高频滤波电容&#xff0c;用来进行高频成分的滤波&#xff0c;这种一大一小两个电容相并联的电路在电源电路中十分常见。1.高…

婚庆网站设计自己做网站可以用私有云吗

一、字符设备驱动结构 1. cdev结构体 在Linux内核中&#xff0c;使用cdev结构体来描述一个字符设备 struct cdev {struct kobject kobj; //内嵌kobject对象struct module *owner; //所属的模块const struct file_operations *ops; //该设备的文件操作结构体struct list_head…

交互式网站是什么意思淘宝网站建设评价表

1&#xff09;Open-Resume 介绍 GitHub&#xff1a; https://github.com/xitanggg/open-resume Open-Resume 是一款功能强大的开源 简历生成器 和 简历解析器 。可以帮助我们快速的生成个人简历&#xff0c;并定制化不同的主题和布局风格。该项目的目标是为每个人提供免费的现…

建设银行在上海的招聘网站海洋网络

在Flowable 6.8.0中&#xff0c;以下是每个表的作用并列出每张表的所有字段及其含义&#xff1a; act_evt_log (用于记录流程引擎事件的日志) log_nr&#xff1a;日志编号type&#xff1a;事件类型proc_def_id&#xff1a;流程定义IDproc_inst_id&#xff1a;流程实例IDexecuti…

百度推广做网站吗网络运营商怎么联系

摘要: 拉马努金Q函数在算法分析中的应用&#xff0c;初步体验 【对算法&#xff0c;数学&#xff0c;计算机感兴趣的同学&#xff0c;欢迎关注我哈&#xff0c;阅读更多原创文章】 我的网站&#xff1a;潮汐朝夕的生活实验室 我的公众号&#xff1a;算法题刷刷 我的知乎&#x…

成都网站建设常见问题合肥昱天建设有限公司网站

BulkLoader提供简单的载入函数&#xff0c;不管要载入的是xml、swf还是声音文件&#xff0c;都只使用同一接口。功能强大&#xff0c;十分推荐。 用法&#xff0c;载入xml文件&#xff1a; var bulkLoader:BulkLoader new BulkLoader(main loading);bulkLoader.add(my_xml_fil…

济南建设网站的公司哪家好简单的网站怎样做

Linux是一个强大的操作系统&#xff0c;拥有许多内建的命令。以下是常见的Linux命令及其简单的解释和用法&#xff1a; ls&#xff1a;列出目录内容。 来源&#xff1a;list。用法&#xff1a;ls、ls -l、ls -a cd&#xff1a;改变当前目录。 来源&#xff1a;change director…

小公司怎样自己建网站投资网

中颖51芯片学习5. 类EEPROM操作 一、SH79F9476 Flash存储空间1. 特性2. 分区3. OP_EEPROMSIZE选项设置3. 编程接口4. 代码保护控制模式简介&#xff08;1&#xff09;**代码保护模式0&#xff1a;**&#xff08;2&#xff09;**代码保护模式1&#xff1a;**&#xff08;3&#…

深圳做网站de公司免费网站模版

工作经常使用的SQL整理&#xff0c;实战篇&#xff08;一&#xff09; 原文:工作经常使用的SQL整理&#xff0c;实战篇&#xff08;一&#xff09;工作经常使用的SQL整理&#xff0c;实战篇&#xff0c;地址一览&#xff1a; 工作经常使用的SQL整理&#xff0c;实战篇&#xff…