1. 程式人生 > >AOP Proxy 物件建立過程

AOP Proxy 物件建立過程

由《Spring的IOC的原始碼解析(三)》繼續分析!首先介紹一下容器名稱空間控制代碼 ContextNamespaceHandler位置:spring-context-*.jar的META-INF/spring-handlersContextNamespaceHandler的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 idList<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) {    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 MethodBeforeAdviceInterceptorAfterReturningAdvice AfterReturningAdviceInterceptorThrowsAdvice 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 codeif (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()方法,暫時不研究了!