欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

Spring aop 分析之一

系統 1935 0

Spring aop 分析之一

?

分析Spring之前先看一個demo, 以對AOP有一個直觀的了解:

    package com.test.aop;

import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;

public class TestAOP {
	public static void main(String[] args) {
		ProxyFactory f = new ProxyFactory();

		// 設置代理目標
		f.setTarget(new Hello());

		// 設置一個前置通知
		f.addAdvice(new MethodBeforeAdvice() {
			@Override
			public void before(Method method, Object[] args, Object target)
					throws Throwable {
				System.out.println("start hello aop.....");
			}
		});
		// 取得代理對象
		IHello h = (IHello) f.getProxy();

		h.hello();
	}
}

interface IHello {
	public void hello();
}

class Hello implements IHello {
	@Override
	public void hello() {
		System.out.println("hello aop");
	}
}

  


執行結果:
start hello aop.....
hello aop


二:
上述demo中IHello接口類型是通過
IHello h = (IHello) f.getProxy(); 方式獲取的,f.getProxy()做了什么處理,
來看下getProxy()方法:


Spring aop 分析之一
?

可以看出, 創建的AopProxy對象可能是 Cglib2AopProxy, JdkDynamicAopProxy, ProxyFactory .

這里只關注 JdkDynamicAopProxy


Spring aop 分析之一
?

JdkDynamicAopProxy部分實現:

    	public Object getProxy() {
		return getProxy(ClassUtils.getDefaultClassLoader());
	}

	public Object getProxy(ClassLoader classLoader) {
		if (logger.isDebugEnabled()) {
			logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
		}
		Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	}

  
?


注:
Class[] proxiedInterfaces= AopProxyUtils.completeProxiedInterfaces(this.advised); // 這里獲取的proxiedInterfaces 包含了IHello接口

Return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); //返回的對象實現了 proxiedInterfaces 中的接口, 而proxiedInterfaces中包含IHello接口, 故可以被轉換成 IHello類型



接下去看看調用代理對象的 hello方法時會做什么:
當調用hello()時會進入到下面的invoke函數

    /**
	 * Implementation of <code>InvocationHandler.invoke</code>.
	 * <p>Callers will see exactly the exception thrown by the target,
	 * unless a hook method throws an exception.
	 */
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		MethodInvocation invocation = null;
		Object oldProxy = null;
		boolean setProxyContext = false;

		TargetSource targetSource = this.advised.targetSource;
		Class targetClass = null;
		Object target = null;

		try {
			
			Object retVal = null;

			target = targetSource.getTarget();
			if (target != null) {
				targetClass = target.getClass();
			}
			// Get the interception chain for this method.
			List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);   // 得到攔截器鏈

			if (chain.isEmpty()) { // 如果攔截器鏈為空, 就直接通過java反射調用目標對象的方法
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
			}
			else {
			    
				invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				
				retVal = invocation.proceed(); // 先執行攔截器鏈,等所有攔截器執行完后再執行目標對象方法
			}
			
			if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy) &&
					!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
				retVal = proxy;
			}
			return retVal;
		}
		finally {
			if (target != null && !targetSource.isStatic()) {
				// Must have come from TargetSource.
				targetSource.releaseTarget(target);
			}
			if (setProxyContext) {
				// Restore old proxy.
				AopContext.setCurrentProxy(oldProxy);
			}
		}
	}

  
?


invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();?? //? 這里是怎么來執行攔截器的, 從ReflectiveMethodInvocation構造函數可以知道,invocation實例持有一個攔截器鏈
通過 invocation.proceed() 方法又是如何遍歷攔截器的呢?


來看proceed方法:

    public Object proceed() throws Throwable {
		//	We start with an index of -1 and increment early.
	 	// currentInterceptorIndex 當前攔截器執行索引, 如果已執行完畢所有攔截器, 則調用目標對象方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint(); // 調用目標對象方法
		}

         // 得到一個攔截器
		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;
			if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
				return dm.interceptor.invoke(this); // 將this作為參數傳入interceptor.invoke, interceptor中有一個通知, 執行完通知后,又會調用proceed方法, 這樣就形成一個遞歸調用過程, 直到所有處理器都便利完成
			}
			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);
		}
	}

  
?



最后以一個demo來 說明攔截器和MethodInvocation 之間相互調用過程

    package com.test.aop;

import java.util.ArrayList;
import java.util.List;

public class Test {
	public String test() {
		return "hello test";
	}
	public static void main(String[] args) {
		// 創建通知1
		Advice advice1 = new Advice() {
			@Override
			public void advice() {
				System.out.println("advice1....");

			}
		};
		
		// 創建通知2
		Advice advice2 = new Advice() {
			@Override
			public void advice() {
				System.out.println("advice2....");

			}
		};
		
		// 創建攔截器鏈
		List<Interceptor> interceptorList = new ArrayList<Interceptor>();
		interceptorList.add(new Interceptor(advice1));
		interceptorList.add(new Interceptor(advice2));
		
		// 創建目標對象
		Test target = new Test();

		// 創建Invocation
		Invocation invocation = new Invocation(interceptorList, target);
		
		Object ret = invocation.proceed(); // start
		
		System.out.println(ret);
	}

}

/**
 * 模擬攔截器
 * 
 */
class Interceptor {
	private Advice advice;

	public Interceptor(Advice advice) {
		this.advice = advice;
	}

	public Object invoke(Invocation invocation) {
		advice.advice(); // 先執行通知
		return invocation.proceed();
	}
}

/**
 * 模擬通知
 * 
 */
interface Advice {
	public void advice();
}

/**
 * 模擬調用
 * 
 */
class Invocation {
	private int interceptorIndex = -1; // 當前攔截器鏈索引
	private List<Interceptor> interceptorList; // 持有的攔截器鏈
	private Test target;

	public Invocation(List<Interceptor> interceptorList, Test target) {
		this.interceptorList = interceptorList;
		this.target = target;
	}

	public Object proceed() {
		if (++interceptorIndex >= interceptorList.size()) {
			return target.test();
		}
		Interceptor interceptor = interceptorList.get(interceptorIndex);
		return interceptor.invoke(this);// 將當前實例作為invoke參數傳入
	}
}
  

?


執行結果:
advice1....
advice2....
hello test

Spring aop 分析之一


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 夜本色| 欧美影院推理片免费看 | 欧美色欧美亚洲高清在线视频 | 久久久大片 | 久久久久久久免费看 | 日韩欧美一区二区不卡 | 国产欧美一区二区精品忘忧草 | 91麻豆精品国产91久久久久久 | 这里精品| 艹逼| 九九久久99 | 波多野吉衣一区二区 | 日韩城人网站 | 欧美13videosex性极品 | 999久久久精品视频在线观看 | 成人黄色短视频在线观看 | 欧美综合图区亚欧综合图区 | 免费观看黄色小视频 | 国产成年网站v片在线观看 中文字幕在线免费视频 | 国产精品久久久久久婷婷天堂 | 亚洲第一第二区 | 91青青国产在线观看免费 | a级毛片在线免费观看 | 国产精品毛片久久久久久 | 国产喷水视频 | 久久久久久高潮国产精品视 | 91一区二区三区在线观看 | 亚洲人在线视频 | 黄色av网站在线免费观看 | 青草免费观看 | 古代级a毛片免费观看 | 亚洲不卡视频 | 国产一区二区三区 | 奇米四色在线观看 | 日韩在线黄色 | 亚洲精品国产自在久久出水 | 久久精品91久久久久久再现 | 国产精品爱啪在线线免费观看 | 日韩影视在线 | 欧美一区二区三区爽大粗免费 | 亚洲精品一区专区 |