[Spring]Spring AOP创建动态代理的过程 您所在的位置:网站首页 aop使用过程 [Spring]Spring AOP创建动态代理的过程

[Spring]Spring AOP创建动态代理的过程

2023-09-24 05:33| 来源: 网络整理| 查看: 265

Spring AOP的大致流程

我们在之前的2章中,知晓了Spring AOP在BeanPostProcessor的几个关键接口做了介入,分为几个关键点:

将切面类进行解析成advisors,其中包括解析XML和被@Aspect注解标注的Java切面类. 在初始化Bean的阶段,将advisors对当前Bean进行筛选,获取到当前Bean匹配的advisors. 进行动态代理类的创建.

今天,我们就来看看动态代理类在Spring AOP中是怎样去创建出来的.

创建动态代理的入口:wrapIfNecessary org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { // beanName不为空,并且存在于targetSourcedBeans中,也就是自定义的TargetSource被解析过了 if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { return bean; } // 如果Bean为advisedBeans,也不需要被代理 if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } // isInfrastructureClass和shouldSkip的作用: // 识别切面类,加载切面类成advisors // 为什么又执行一次是因为存在循环依赖的情况下无法加载advisor if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // Create proxy if we have advice. // 返回匹配当前Bean的所有Advice、Advisor、Interceptor Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); // 创建Bean对应的代理,SingletonTargetSource用于封装实现类的信息 Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } // 下次代理的时候直接从缓存拿出判断,不需要重复代理 this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } targetSourcedBeans存储了用户自定义的targetSource,这部分的bean在org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation中已经进行了createProxy的处理,所以在自动化代理的环节中,要过滤掉这部分的bean. advisedBeans存储了已经被Spring AOP处理过的bean,这部分的bean也是需要进行过滤的. 进行isInfrastructureClass和shouldSkip的处理,这两个方法在之前的文章已经做了详细的解析,它们的主要作用是:识别切面类、解析切面类。之所以再重复调用一次,是为了收尾的工作. getAdvicesAndAdvisorsForBean获取当前bean匹配的advisors. 将当前bean缓存到advisedBeans,创建动态代理-createProxy,缓存proxyType. 这里无论是否能获取到bean的advisors,都会做缓存到advisedBeans的步骤.已确保不重复处理同一个bean. 创建动态代理:createProxy org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy protected Object createProxy(Class beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) { // 如果beanFactory是ConfigurableListableBeanFactory的类型,暴露目标类 if (this.beanFactory instanceof ConfigurableListableBeanFactory) { AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass); } // 创建一个ProxyFactory,当前ProxyCreator在创建代理时,将需要用到的字段赋值到ProxyFactory中去 ProxyFactory proxyFactory = new ProxyFactory(); // 将当前的AnnotationAwareAspectJAutoProxyCreator对象的属性赋值给ProxyFactory对象 // 加载一些ProxyConfig proxyFactory.copyFrom(this); // 处理proxyTargetClass属性 // 如果希望使用CGLIB进行代理,配置proxyTargetClass为true if (!proxyFactory.isProxyTargetClass()) { // 检查相应BeanDefinition的“ preserveTargetClass”属性 if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); } else { // 1. 有接口的,调用一次或者多次:proxyFactory.addInterface(ifc); // 2. 没有接口的,调用: proxyFactory.setProxyTargetClass(true); evaluateProxyInterfaces(beanClass, proxyFactory); } } // 这个方法主要是对前面传递进来的横切逻辑实例进行包装 // specificInterceptors中有Advice和Interceptor,它们都会被包装成Advisor // 调用的先后顺序,通过方法中的applyCommonInterceptorsFirst参数进行设置 Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); proxyFactory.addAdvisors(advisors); proxyFactory.setTargetSource(targetSource); // 扩展实现,子类可以定制proxyFactory customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy); // 设置preFiltered的属性值,默认为false.子类:AbstractAdvisorAutoProxyCreator修改为true // preFiltered字段的意思是:是否为特定目标类筛选Advisor // 该字段和DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice获取所有的Advisors // CglibAopProxy和JdkDynamicAopProxy都会调用此方法,然后递归执行所有的advisor if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); } return proxyFactory.getProxy(getProxyClassLoader()); } 如果当前的beanFactory属于ConfigurableListableBeanFactory类型,给当前bean对应的BeanDefinition设置上属性"originalTargetClass"为targetClass. 先new一个ProxyFactory实例,并根据AnnotationAwareAspectJAutoProxyCreator的配置进行proxyTargetClass、optimize、exposeProxy、frozen、opaque的属性设置. Spring不仅提供了对所有bean生效的proxyTargetClass设置,也提供了对单个bean的动态代理配置preserveTargetClass. 调用buildAdvisors对specificInterceptors进行适配,封装成advisor.有兴趣的可以看看org.springframework.aop.framework.adapter.DefaultAdvisorAdapterRegistry#wrap. 配置advisors、targetSource、frozen等属性后,进行动态代理的创建. proxyFactory.getProxy(getProxyClassLoader()),进行动态代理生成. getProxy: 根据当前bean选择JDK或者CGLIB动态代理 org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader) public Object getProxy(@Nullable ClassLoader classLoader) { // 首先获取AopProxy对象,其主要有两个实现:JdkDynamicAopProxy和ObjenesisCglibAopProxy // 分别用于JDK和CGLIB代理类的生成,其getProxy方法则用于获取具体的代理对象 return createAopProxy().getProxy(classLoader); }

ProxyFactory是ProxyCreatorSupport的子类,在ProxyCreatorSupport中有一个createAopProxy方法,从这里可以获取到具体的代理工厂类.

org.springframework.aop.framework.ProxyCreatorSupport#createAopProxy protected final synchronized AopProxy createAopProxy() { // 激活AdvisedSupportListener监听器 if (!this.active) { activate(); } return getAopProxyFactory().createAopProxy(this); } activate方法主要是用来激活AdvisedSupportListener的. 重点方法是这个:getAopProxyFactory().createAopProxy(this);其中,getAopProxyFactory中存储了一个DefaultAopProxyFactory,它实现了AopProxyFactory接口,接口方法createAopProxy才是真正获取代理工厂的地方. org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (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的代理类(Proxy子类) // 使用JDK动态代理 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } // 使用CGLIB动态代理 return new ObjenesisCglibAopProxy(config); } else { // 接口->JDK动态代理 return new JdkDynamicAopProxy(config); } }

这里就会看到我们很熟悉的一个逻辑:实现了接口的bean,Spring会使用JDK动态代理;否则使用CGLIB代理.

工厂模式:JdkDynamicAopProxy和ObjenesisCglibAopProxy

代理策略选择

由于篇幅的原因,我选择讲解JdkDynamicAopProxy这种模式生成代理的源码解析.

org.springframework.aop.framework.JdkDynamicAopProxy#getProxy(java.lang.ClassLoader) public Object getProxy(@Nullable ClassLoader classLoader) { if (logger.isTraceEnabled()) { logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource()); } // 获取完整的代理接口 Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); // JdkDynamicAopProxy本身实现了InvocationHandler接口 return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); }

关于JDK如何生成动态代理的原理,这里不做过多的分析了,这在我之前的博客中有关于JDK和CGLIB生成Proxy的文章,不了解的读者可以去看看: 点我前往 在生成代理之后,Proxy就会调用InvocationHandler.invoke方法,所以关于Spring AOP的代理拦截链执行流程,我们直接去到invoke解析即可。

org.springframework.aop.framework.JdkDynamicAopProxy#invoke final class JdkDynamicAopProxy implements AopProxy, InvocationHandler

首先,JdkDynamicAopProxy实现了InvocationHandler接口,动态代理类最终会执行InvocationHandler.invoke.

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]); } // hashcode方法不需要代理 else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { // The target does not implement the hashCode() method itself. return hashCode(); } // 如果当前方法是Spring织入的DecoratingProxy接口中的方法,返回目标对象的class类型 else if (method.getDeclaringClass() == DecoratingProxy.class) { // There is only getDecoratedClass() declared -> dispatch to proxy config. return AopProxyUtils.ultimateTargetClass(this.advised); } // 如果被代理的对象本身实现了Advised接口,则证明该类里面的方法已经被代理了,直接执行即可 else if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) { // Service invocations on ProxyConfig with the proxy config... return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); } Object retVal; // 是否暴露代理引用 if (this.advised.exposeProxy) { // Make invocation available if necessary. oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } // Get as late as possible to minimize the time we "own" the target, // in case it comes from a pool. // 获取目标类 target = targetSource.getTarget(); Class targetClass = (target != null ? target.getClass() : null); // Get the interception chain for this method. // 获取方法的拦截链 List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); // Check whether we have any advice. If we don't, we can fallback on direct // reflective invocation of the target, and avoid creating a MethodInvocation. // 如果该方法上没有匹配的拦截器,直接反射调用Method.invoke(target,args) if (chain.isEmpty()) { // We can skip creating a MethodInvocation: just invoke the target directly // Note that the final invoker must be an InvokerInterceptor so we know it does // nothing but a reflective operation on the target, and no hot swapping or fancy proxying. Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } else { // We need to create a method invocation... // 创建ReflectiveMethodInvocation 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); } } } Spring AOP不对equals和hashCode做代理. 如果当前方法是Spring织入的DecoratingProxy接口中的方法,返回目标对象的class类型. 如果被代理的对象本身实现了Advised接口,则证明该类里面的方法已经被代理了,直接执行即可 查看当前配置判断是否暴露代理引用,可以来解决this调用引起的代理失效等问题. 从targetSource中获取target信息.获取当前method的拦截链路.getInterceptorsAndDynamicInterceptionAdvice会对method的拦截链进行缓存,如果没有缓存,会执行org.springframework.aop.framework.DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice重新对method进行match. 从getInterceptorsAndDynamicInterceptionAdvice获取到chain之后,如果chain为空,那么直接激活method. 如果chain不为空,生成ReflectiveMethodInvocation,从JavaDoc可以知道,这是一个Spring实现了AOP Alliance MethodInvocation接口的类,关键方法:invokeJoinpoint(激活连接点方法)、proceed(执行拦截链逻辑). 执行proceed. 处理返回值。包装此返回值(如果有必要作为代理),并验证没有将null作为原语返回。这是什么意思呢:假设方法返回的是int,增强around方法返回了null,这就会报错,因为基础数据类型都有默认值. 释放资源、重新设置一次代理引用.

这里最关键的的看chain的执行过程,整个Spring AOP拦截链执行的过程采用了一种递归的方式,值得一品.

代理类执行链路 org.springframework.aop.framework.ReflectiveMethodInvocation#proceed public Object proceed() throws Throwable { // We start with an index of -1 and increment early. // 如果拦截器执行完了,则执行连接点 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } // 从0开始执行,每次递归进来都会+1 Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); 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. // 动态匹配失败,进入下一个拦截器 return proceed(); } } else { // It's an interceptor, so we just invoke it: The pointcut will have // been evaluated statically before this object was constructed. // 执行当前拦截器 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } } 在遇到AfterThrowing、AfterRetruning、After这类advice的时候,它们会执行mi.proceed回到chain中. 回到chain中后,列表索引自增,往下执行下一个advice. 依次递归,直到遇到Around通知,执行around. 在around中执行joinPoint.proceed又会回到chain中. 递归到Before,执行before,然后回到around的后置代码块中. 回溯到after、afterReturning,如果有异常,执行afterThrowing. 执行流程图

proceed

总结 1. 生成代理类通过工厂模式进行生成,实现接口默认使用JDK动态代理,否则使用CGLIB 2. Spring AOP通过后置处理器的postProcessAfterInitialization方法调用wrapIfNessary对Bean进行代理并替换. 3. 代理类执行拦截链通过chain进行递归proceed来执行每个通知的方法


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有