日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

调用代理方法

發(fā)布時間:2024/4/13 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 调用代理方法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

分析調(diào)用邏輯之前先上類圖,看看Spring 中主要的AOP 組件:

上面我們已經(jīng)了解到Spring 提供了兩種方式來生成代理方式有JDKProxy 和CGLib。下面我們來研究一下Spring 如何使用JDK 來生成代理對象,具體的生成代碼放在JdkDynamicAopProxy 這個類中,直接上相關(guān)代碼:

/*** 獲取代理類要實現(xiàn)的接口,除了Advised對象中配置的,還會加上SpringProxy, Advised(opaque=false)* 檢查上面得到的接口中有沒有定義 equals或者hashcode的接口* 調(diào)用Proxy.newProxyInstance創(chuàng)建代理對象*/ @Override public Object getProxy(@Nullable ClassLoader classLoader) {if (logger.isDebugEnabled()) {logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());}Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); }

通過注釋我們應(yīng)該已經(jīng)看得非常明白代理對象的生成過程,此處不再贅述。下面的問題是,代理對象生成了,那切面是如何織入的?

我們知道InvocationHandler 是JDK 動態(tài)代理的核心,生成的代理對象的方法調(diào)用都會委托到InvocationHandler.invoke()方法。而從JdkDynamicAopProxy 的源碼我們可以看到這個類其實也實現(xiàn)了InvocationHandler,下面我們分析Spring AOP 是如何織入切面的,直接上源碼看invoke()方法:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {MethodInvocation invocation;Object oldProxy = null;boolean setProxyContext = false;TargetSource targetSource = this.advised.targetSource;Object target = null;try {//eqauls()方法,具目標對象未實現(xiàn)此方法if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {// The target does not implement the equals(Object) method itself.return equals(args[0]);}//hashCode()方法,具目標對象未實現(xiàn)此方法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);}//Advised接口或者其父接口中定義的方法,直接反射調(diào)用,不應(yīng)用通知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.//獲取可以應(yīng)用到此方法上的Interceptor列表List<Object> 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.//如果沒有可以應(yīng)用到此方法的通知(Interceptor),此直接反射調(diào)用 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...//創(chuàng)建MethodInvocationinvocation = 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);}} }

主要實現(xiàn)思路可以簡述為:首先獲取應(yīng)用到此方法上的通知鏈(Interceptor Chain)。如果有通知,則應(yīng)用通知,并執(zhí)行JoinPoint;如果沒有通知,則直接反射執(zhí)行JoinPoint。而這里的關(guān)鍵是通知鏈是如何獲取的以及它又是如何執(zhí)行的呢?現(xiàn)在來逐一分析。首先,從上面的代碼可以看到,通知鏈是通過Advised.getInterceptorsAndDynamicInterceptionAdvice()這個方法來獲取的,我們來看下這個方法的實現(xiàn)邏輯:

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {MethodCacheKey cacheKey = new MethodCacheKey(method);List<Object> cached = this.methodCache.get(cacheKey);if (cached == null) {cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);this.methodCache.put(cacheKey, cached);}return cached; }

通過上面的源碼我們可以看到, 實際獲取通知的實現(xiàn)邏輯其實是由AdvisorChainFactory 的getInterceptorsAndDynamicInterceptionAdvice()方法來完成的,且獲取到的結(jié)果會被緩存。下面來分析getInterceptorsAndDynamicInterceptionAdvice()方法的實現(xiàn):

/*** 從提供的配置實例config中獲取advisor列表,遍歷處理這些advisor.如果是IntroductionAdvisor,* 則判斷此Advisor能否應(yīng)用到目標類targetClass上.如果是PointcutAdvisor,則判斷* 此Advisor能否應(yīng)用到目標方法method上.將滿足條件的Advisor通過AdvisorAdaptor轉(zhuǎn)化成Interceptor列表返回.*/ @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.List<Object> interceptorList = new ArrayList<>(config.getAdvisors().length);Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());//查看是否包含IntroductionAdvisorboolean hasIntroductions = hasMatchingIntroductions(config, actualClass);//這里實際上注冊一系列AdvisorAdapter,用于將Advisor轉(zhuǎn)化成MethodInterceptorAdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();for (Advisor advisor : config.getAdvisors()) {if (advisor instanceof PointcutAdvisor) {// Add it conditionally.PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {//這個地方這兩個方法的位置可以互換下//將Advisor轉(zhuǎn)化成InterceptorMethodInterceptor[] interceptors = registry.getInterceptors(advisor);//檢查當前advisor的pointcut是否可以匹配當前方法MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {if (mm.isRuntime()) {// 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));}}}}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; }

這個方法執(zhí)行完成后,Advised 中配置能夠應(yīng)用到連接點(JoinPoint)或者目標類(Target Object)的Advisor 全部被轉(zhuǎn)化成了MethodInterceptor,接下來我們再看下得到的攔截器鏈是怎么起作用的。

// 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. //如果沒有可以應(yīng)用到此方法的通知(Interceptor),此直接反射調(diào)用 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...//創(chuàng)建MethodInvocationinvocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);// Proceed to the joinpoint through the interceptor chain.retVal = invocation.proceed(); }

從這段代碼可以看出, 如果得到的攔截器鏈為空, 則直接反射調(diào)用目標方法, 否則創(chuàng)建MethodInvocation,調(diào)用其proceed()方法,觸發(fā)攔截器鏈的執(zhí)行,來看下具體代碼:

@Override @Nullable public Object proceed() throws Throwable {// We start with an index of -1 and increment early.//如果Interceptor執(zhí)行完了,則執(zhí)行joinPointif (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {return invokeJoinpoint();}Object interceptorOrInterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);//如果要動態(tài)匹配joinPointif (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {// Evaluate dynamic method matcher here: static part will already have// been evaluated and found to match.InterceptorAndDynamicMethodMatcher dm =(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;//動態(tài)匹配:運行時參數(shù)是否滿足匹配條件if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {return dm.interceptor.invoke(this);}else {// Dynamic matching failed.// Skip this interceptor and invoke the next in the chain.//動態(tài)匹配失敗時,略過當前Intercetpor,調(diào)用下一個Interceptorreturn proceed();}}else {// It's an interceptor, so we just invoke it: The pointcut will have// been evaluated statically before this object was constructed.//執(zhí)行當前Intercetporreturn ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);} }

至此,通知鏈就完美地形成了。我們再往下來看invokeJoinpointUsingReflection()方法,其實就是反射調(diào)用:

public static Object invokeJoinpointUsingReflection(@Nullable Object target, Method method, Object[] args)throws Throwable {// Use reflection to invoke the method.try {ReflectionUtils.makeAccessible(method);return method.invoke(target, args);}catch (InvocationTargetException ex) {// Invoked method threw a checked exception.// We must rethrow it. The client won't see the interceptor.throw ex.getTargetException();}catch (IllegalArgumentException ex) {throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +method + "] on target [" + target + "]", ex);}catch (IllegalAccessException ex) {throw new AopInvocationException("Could not access method [" + method + "]", ex);} }

?

總結(jié)

以上是生活随笔為你收集整理的调用代理方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。