天天看點

AOP Proxy 對象建立過程

由《Spring的IOC的源碼解析(三)》繼續分析! 首先介紹一下容器命名空間句柄 ContextNamespaceHandler 位置:spring-context-*.jar的META-INF/spring-handlers 容器命名空間句柄: http\:// www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler ContextNamespaceHandler的init方法實作如下,      registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());     registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());     registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());     registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());     registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());     registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());     registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());     registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());

當 ContextNamespaceHandler在解析标簽的時候,會調用每種标簽的解析器,解析過程就會調用 AopNamespaceUtils為目前類型的标簽 嘗試 注冊相應的BPP;下邊給出一些示例,格式為: {标簽-标簽解析器-注冊的BPP}     config/ ConfigBeanDefinitionParser/ AspectJAwareAdvisorAutoProxyCreator     aspectj-autoproxy/ AspectJAutoProxyBeanDefinitionParser/ AnnotationAwareAspectJAutoProxyCreator     load-time-weaver/ LoadTimeWeaverBeanDefinitionParser/沒有     component-scan/ ComponentScanBeanDefinitionParser/沒有

繼續分析AOP Proxy對象的生成過程! (1)擷取能夠處理目标類的advisor 首先是調用AbstractAdvisorAutoProxyCreator. getAdvicesAndAdvisorsForBean()方法,然後調用: protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {     List<Advisor> candidateAdvisors = findCandidateAdvisors(); //這個方法就是去beanFactory中查詢全部Advisor類型的bean,然後初始化;參見(a)     List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);//參看(b)     extendAdvisors(eligibleAdvisors);     if (!eligibleAdvisors.isEmpty()) {     eligibleAdvisors = sortAdvisors(eligibleAdvisors);//排序     }     return eligibleAdvisors; } (a) 擷取并初始化Advisor,實作邏輯在 BeanFactoryAdvisorRetrievalHelper.findAdvisorBeans(),其核心代碼是: advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Advisor.class, true, false); //查詢所有注冊在工廠中的Advisor的bean name or id List<Advisor> advisors = new LinkedList<>();                         advisors.add(this.beanFactory.getBean(name, Advisor.class)); //初始化Advisor,同時也會初始化Advisor中的advice,生成一個advice執行個體;

(b) 往後又調用 AopUtils.findAdvisorsThatCanApply()方法; findAdvisorsThatCanApply調用的核心函數就是: public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {     if (advisor instanceof IntroductionAdvisor) {         return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass); //advisor是 IntroductionAdvisor的比對過程     }     else if (advisor instanceof PointcutAdvisor) {//正常使用AOP,都是這種advisor         PointcutAdvisor pca = (PointcutAdvisor) advisor;         return canApply(pca.getPointcut(), targetClass, hasIntroductions); //advisor是 PointcutAdvisor的比對過程     }     else {         // It doesn't have a pointcut so we assume it applies.         return true; //其他的 advisor 預設要處理     } } pointcut的比對過程如下: public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {     Assert.notNull(pc, "Pointcut must not be null");     if (!pc.getClassFilter().matches(targetClass)) { //擷取advisor中的pointcut對象,關于pointcut的使用,請參看《 spring中的pointcut 》;這裡相當于把所有的advisor中的pointcut都拿來比對一遍,看看是否滿足         return false;     }

    MethodMatcher methodMatcher = pc.getMethodMatcher();     if (methodMatcher == MethodMatcher.TRUE) {         // No need to iterate the methods if we're matching any method anyway...         return true;     }

    IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;     if (methodMatcher instanceof IntroductionAwareMethodMatcher) {         introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;     }

    Set<Class<?>> classes = new LinkedHashSet<>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));     classes.add(targetClass);     for (Class<?> clazz : classes) {         Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);         for (Method method : methods) {             if ((introductionAwareMethodMatcher != null &&                     introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||                     methodMatcher.matches(method, targetClass)) {                 return true;             }         }     }

    return false; }

最終,傳回所有适合代理類的advisor

(2)建立AOP代理 protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) {     if (this.beanFactory instanceof ConfigurableListableBeanFactory) {         AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass); // 為bean設定屬性org.springframework.aop.framework.autoproxy.AutoProxyUtils.originalTargetClass,值是beanClass     }     ProxyFactory proxyFactory = new ProxyFactory(); //代理工廠     proxyFactory.copyFrom(this); //為代理工廠設定proxyTargetClass,是否初始化等參數

    if (!proxyFactory.isProxyTargetClass()) { //預設應該條件為true,進入if         if (shouldProxyTargetClass(beanClass, beanName)) { //判斷是代理類,還是代理類的接口;判斷的邏輯就是看bean的定義中,屬性名為 org.springframework.aop.framework.autoproxy.AutoProxyUtils.preserveTargetClass的屬性的值是否設定為了true。暫時隻知道 ConfigurationClassPostProcessor可以配置這個屬性為true;預設是false,即代理接口             proxyFactory.setProxyTargetClass(true); //代理目标類,标記 proxyTargetClass=true         }         else {             evaluateProxyInterfaces(beanClass, proxyFactory); //代理目标類的接口;如果是可以代理的接口,就把接口加入到ProxyFactory中,見(a)         }     }     Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); //合并共用和指定攔截器到advisor,可以把advisor叫做增強器;見(b)      proxyFactory.addAdvisors(advisors); //這是增強器     proxyFactory.setTargetSource(targetSource);//設定執行個體對象,用于代理調用代理方法是使用     customizeProxyFactory(proxyFactory);

    proxyFactory.setFrozen(this.freezeProxy);     if (advisorsPreFiltered()) {         proxyFactory.setPreFiltered(true);     }     return proxyFactory.getProxy(getProxyClassLoader()); //生成代理對象,見(c) }

(a) 可代理的接口的定義 至少有一個方法的接口 或者 protected boolean isInternalLanguageInterface(Class<?> ifc) {     return (ifc.getName().equals("groovy.lang.GroovyObject") ||             ifc.getName().endsWith(".cglib.proxy.Factory") ||             ifc.getName().endsWith(".bytebuddy.MockAccess")); } 傳回false的接口 或者 protected boolean isConfigurationCallbackInterface(Class<?> ifc) {     return (InitializingBean.class == ifc || DisposableBean.class == ifc || Closeable.class == ifc ||             AutoCloseable.class == ifc || ObjectUtils.containsElement(ifc.getInterfaces(), Aware.class)); } 傳回false的接口

(b)合并共用和指定攔截器到advisor,預設沒有共用攔截器 protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {     Advisor[] commonInterceptors = resolveInterceptorNames(); //把定義的攔截器包裝成advisor,傳回     List<Object> allInterceptors = new ArrayList<>();     if (specificInterceptors != null) {         allInterceptors.addAll(Arrays.asList(specificInterceptors));         if (commonInterceptors.length > 0) {             if (this.applyCommonInterceptorsFirst) { //預設把攔截器的執行放在最前邊執行                 allInterceptors.addAll(0, Arrays.asList(commonInterceptors));             }             else {                 allInterceptors.addAll(Arrays.asList(commonInterceptors));             }         }     }     Advisor[] advisors = new Advisor[allInterceptors.size()];     for (int i = 0; i < allInterceptors.size(); i++) {         advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i)); //包裝advisor,适配方法是 DefaultAdvisorAdapterRegistry.wrap()     }     return advisors; }

适配過程: public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {     if (adviceObject instanceof Advisor) {         return (Advisor) adviceObject; //如果是advisor對象,不用處理     }     if (!(adviceObject instanceof Advice)) { //隻能是advicor or advice         throw new UnknownAdviceTypeException(adviceObject);     }     Advice advice = (Advice) adviceObject; //advice對象都包裝成 DefaultPointcutAdvisor對象     if (advice instanceof MethodInterceptor) {         // So well-known it doesn't even need an adapter.         return new DefaultPointcutAdvisor(advice);     }     for (AdvisorAdapter adapter : this.adapters) {         // Check that it is supported.         if (adapter.supportsAdvice(advice)) {             return new DefaultPointcutAdvisor(advice);         }     }     throw new UnknownAdviceTypeException(advice); }

(c)代理工廠生成代理對象 這裡一直沒有讀懂aopProxyFactory對象的執行個體話,這裡假定aopProxyFactory就是一個DefaultAopProxyFactory對象; DefaultAopProxyFactory中生成代理對象的方法: 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.");         }         if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {             return new JdkDynamicAopProxy(config);         }         return new ObjenesisCglibAopProxy(config); //類代理,分析過程見【1】     }     else {         return new JdkDynamicAopProxy(config); //接口代理, 分析過程見 【2】     } } 如果不是代理接口,就使用CGLIB位元組碼動态代理;否則使用JDK的動态代理。

【1】 jdk動态代理 JdkDynamicAopProxy.getProxy()方法: public Object getProxy(@Nullable ClassLoader classLoader) {     Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised , true);     findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);     return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); } 是以,傳回的代理對象就是JDK的Proxy.newProxyInstance方法生成的,而且參數需要的 InvocationHandler對象就是目前的JdkDynamicAopProxy對象; 我們知道,JDK動态代理的實作原理就是代理對象在執行目标方法的時候,會檢查目前方法是否被代理?如果被代理,那麼就執行 InvocationHandler的invoke方法代替;

下邊看看JDK動态代理模式下的,代理對象真正執行方法時,切面織入方法的功能是怎樣實作的。 JdkDynamicAopProxy實作 InvocationHandler接口,invoke方法的核心邏輯是: List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); // chain是 InterceptorAndDynamicMethodMatcher連結清單; 參見{1} if (chain.isEmpty()) {      //跳過熱交換,隻是執行目标類的方法,method.invoke     Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);     retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } else {      //建立 method invocation     invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);   //反射方法處理過程,target參數就是被代理類的執行個體      //執行攔截器鍊和方法,參看{4}     retVal = invocation.proceed(); }

{1}把增強器advisors包裝成mathodMatcher鍊的過程 調用DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice()方法, 核心代碼如下: MethodInterceptor[] interceptors = registry.getInterceptors(advisor); // registry是 DefaultAdvisorAdapterRegistry執行個體,這裡就是把advisor中的advice包裝成 MethodInterceptor,見{2} MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); //獲得比對方法;參見{3} if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {     if (mm.isRuntime()) {         for (MethodInterceptor interceptor : interceptors) {             interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)); //采用組合模式,将攔截器對象和比對方法對象放在 InterceptorAndDynamicMethodMatcher對象中,得到傳回值對象;         }     }     else {         interceptorList.addAll(Arrays.asList(interceptors));     } }

{2}例如:下邊是預設包裝關系 MethodBeforeAdvice MethodBeforeAdviceInterceptor AfterReturningAdvice AfterReturningAdviceInterceptor ThrowsAdvice ThrowsAdviceInterceptor 根據advice的解析過程可知,before 類型的advice的目标類就是MethodBeforeAdvice類的子類;advice的pointcut依賴指定的目标類是AspectJExpressionPointcut

{3}由{2}的說明可知,MethodMatcher方法對象的擷取過程就是擷取AspectJExpressionPointcut對象;在pointcut執行個體化時會解析expression表達式,邏輯如下: private PointcutExpression buildPointcutExpression(@Nullable ClassLoader classLoader) {     PointcutParser parser = initializePointcutParser(classLoader);     PointcutParameter[] pointcutParameters = new PointcutParameter[this.pointcutParameterNames.length];     for (int i = 0; i < pointcutParameters.length; i++) {         pointcutParameters[i] = parser.createPointcutParameter(                 this.pointcutParameterNames[i], this.pointcutParameterTypes[i]);     }     return parser.parsePointcutExpression(replaceBooleanOperators(resolveExpression()),  this.pointcutDeclarationScope, pointcutParameters); //expression的對象類是 PointcutExpressionImpl } 需要說明的是,AspectJExpressionPointcut類實作IntroductionAwareMethodMatcher、MethodMatcher接口;

{4}循環處理攔截器鍊,使用matcher比對,然後調用攔截器的invoke方法 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { //所有 advice都調用完之後,調用這裡,但是after advice是逆向調用的,所有代理方法會在after adviec之前之前執行     return invokeJoinpoint(); } //other code if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { //比對;見{5}分析     return dm.interceptor.invoke(this); //調用;參見{6} } else {     // Dynamic matching failed.     // Skip this interceptor and invoke the next in the chain.     return proceed(); //如果比對失敗,跳過目前advisor,繼續下一個 }

{5}可知比對過程就是AspectJExpressionPointcut的matches方法邏輯過程; {6}看看典型advice的處理過程 before advice的 MethodBeforeAdviceInterceptor調用過程如下: public Object invoke(MethodInvocation mi) throws Throwable {     this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() ); // AspectJMethodBeforeAdvice.before方法,這裡就是調用before通知在切面裡定義的執行方法     return mi.proceed(); //跳轉到 ReflectiveMethodInvocation. proceed()方法,實作調用多個advice的功能 }

AspectJMethodBeforeAdvice.before(){     invokeAdviceMethod(getJoinPointMatch(), null, null); }

after-returning的AfterReturningAdviceInterceptor調用過程如下: public Object invoke(MethodInvocation mi) throws Throwable {     Object retVal = mi.proceed(); //跳轉到 ReflectiveMethodInvocation. proceed()方法,實作調用多個advice的功能     this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis()); //調用後處理方法     return retVal; }

AspectJAfterReturningAdvice.afterReturning(){     if (shouldInvokeOnReturnValueOf(method, returnValue)) {         invokeAdviceMethod(getJoinPointMatch(), returnValue, null);     } } 可見,所有的advice都是先執行before advice 再執行after-returning advice ;所有的advice都執行完之後,執行被代理的方法;因為after advice是逆向調用的,是以被代理的方法會在after advice之前調用。

around advice通知是怎麼實作的呢? 看到DefaultAdvisorAdapterRegistry類的wrap方法: if (adviceObject instanceof Advisor) { //advice 不是advisor,跳過     return (Advisor) adviceObject; } if (!(adviceObject instanceof Advice)) {     throw new UnknownAdviceTypeException(adviceObject); } Advice advice = (Advice) adviceObject; if (advice instanceof MethodInterceptor) {     // So well-known it doesn't even need an adapter.     return new DefaultPointcutAdvisor(advice); //advice 都在這裡處理,被适配成 DefaultPointcutAdvisor對象 }

再看攔截器方法鍊——也就是advice的方法封裝,也是DefaultAdvisorAdapterRegistry的方法: public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {     List<MethodInterceptor> interceptors = new ArrayList<>(3);     Advice advice = advisor.getAdvice();     if (advice instanceof MethodInterceptor) { //around advice的處理類 AspectJAroundAdvice實作了 MethodInterceptor接口,是以就是around advice的方法攔截器就是 AspectJAroundAdvice對象         interceptors.add((MethodInterceptor) advice);     }     for (AdvisorAdapter adapter : this.adapters) {         if (adapter.supportsAdvice(advice)) {             interceptors.add(adapter.getInterceptor(advisor));         }     }     if (interceptors.isEmpty()) {         throw new UnknownAdviceTypeException(advisor.getAdvice());     }     return interceptors.toArray(new MethodInterceptor[interceptors.size()]); } 下邊看方法攔截器的調用過程: public Object invoke(MethodInvocation mi) throws Throwable {     if (!(mi instanceof ProxyMethodInvocation)) {         throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);     }     ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;     ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi); //傳回一個 MethodInvocationProceedingJoinPoint對象,這個對象就是在切面中定義的around方法的實參     JoinPointMatch jpm = getJoinPointMatch(pmi);     return invokeAdviceMethod(pjp, jpm, null, null); //調用父類的方法;參見{7} }

{7}advice方法的調用,核心就是下邊這一句 this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs); 解釋: this.aspectJAdviceMethod擷取advice指定方法的Method對象; this.aspectInstanceFactory.getAspectInstance()擷取一個advice所屬切面aspect的執行個體; actualArgs是方法參數; 也就是method.invoke(object,args)而已;

before advice,after-returning advice在調用advice方法時,會調用下一個advice的方法,但是around advice沒有這樣做;事實上,around advice調用下一個advice方法的語句在,切面實作的方法中,從這一點上将,隻有around advice的方法參數是必須要被使用的;而在around advice方法中,可以在point.proceed();語句前後加增強語句,正是“環繞”的意義所在;需要注意的是,如果有多個around advice被執行,那麼point.proceed();語句後面的增強語句的執行過程像堆棧調用,即先被調用的後被執行;

到此,基于JDK的動态代理實作的AOP過程就分析完成了!

【2】 位元組碼代理 ObjenesisCglibAopProxy. getProxy()方法,暫時不研究了!