AOP用來封裝橫切關注點,具體能夠在下面的場景中使用:java
Authentication 權限正則表達式
Caching 緩存編程
Context passing 內容傳遞緩存
Error handling 錯誤處理性能優化
Lazy loading 懶加載框架
Debugging 調試模塊化
logging, tracing, profiling and monitoring 記錄跟蹤 優化 校準性能
Performance optimization 性能優化優化
Persistence 持久化this
Resource pooling 資源池
Synchronization 同步
Transactions 事務
方面(Aspect):一個關注點的模塊化,這個關注點實現可能另外橫切多個對象。事務管理是J2EE應用中一個很好的橫切關注點例子。方面用Spring的 Advisor或攔截器實現。
鏈接點(Joinpoint): 程序執行過程當中明確的點,如方法的調用或特定的異常被拋出。
通知(Advice): 在特定的鏈接點,AOP框架執行的動做。各類類型的通知包括「around」、「before」和「throws」通知。通知類型將在下面討論。許多AOP框架包括Spring都是以攔截器作通知模型,維護一個「圍繞」鏈接點的攔截器鏈。Spring中定義了四個advice: BeforeAdvice, AfterAdvice, ThrowAdvice和DynamicIntroductionAdvice。
切入點(Pointcut): 指定一個通知將被引起的一系列鏈接點的集合。AOP框架必須容許開發者指定切入點:例如,使用正則表達式。 Spring定義了Pointcut接口,用來組合MethodMatcher和ClassFilter,能夠經過名字很清楚的理解, MethodMatcher是用來檢查目標類的方法是否能夠被應用此通知,而ClassFilter是用來檢查Pointcut是否應該應用到目標類上。
引入(Introduction): 添加方法或字段到被通知的類。 Spring容許引入新的接口到任何被通知的對象。例如,你可使用一個引入使任何對象實現 IsModified接口,來簡化緩存。Spring中要使用Introduction, 可有經過DelegatingIntroductionInterceptor來實現通知,經過DefaultIntroductionAdvisor來配置Advice和代理類要實現的接口。
目標對象(Target Object): 包含鏈接點的對象。也被稱做被通知或被代理對象。
AOP代理(AOP Proxy): AOP框架建立的對象,包含通知。 在Spring中,AOP代理能夠是JDK動態代理或者CGLIB代理。
織入(Weaving): 組裝方面來建立一個被通知對象。這能夠在編譯時完成(例如使用AspectJ編譯器),也能夠在運行時完成。Spring和其餘純Java AOP框架同樣,在運行時完成織入。
能夠經過配置文件或者編程的方式來使用Spring AOP。
配置能夠經過xml文件來進行,大概有四種方式:
1. 配置ProxyFactoryBean,顯式地設置advisors, advice, target等
2. 配置AutoProxyCreator,這種方式下,仍是如之前同樣使用定義的bean,可是從容器中得到的其實已是代理對象
3. 經過<aop:config>來配置
4. 經過<aop: aspectj-autoproxy>來配置,使用AspectJ的註解來標識通知及切入點
也能夠直接使用ProxyFactory來以編程的方式使用Spring AOP,經過ProxyFactory提供的方法能夠設置target對象, advisor等相關配置,最終經過 getProxy()方法來獲取代理對象
Spring提供了兩種方式來生成代理對象: JDKProxy和Cglib,具體使用哪一種方式生成由AopProxyFactory根據AdvisedSupport對象的配置來決定。默認的策略是若是目標類是接口,則使用JDK動態代理技術,不然使用Cglib來生成代理。下面咱們來研究一下Spring如何使用JDK來生成代理對象,具體的生成代碼放在JdkDynamicAopProxy這個類中,直接上相關代碼:
/** * <ol> * <li>獲取代理類要實現的接口,除了Advised對象中配置的,還會加上SpringProxy, Advised(opaque=false) * <li>檢查上面獲得的接口中有沒有定義 equals或者hashcode的接口 * <li>調用Proxy.newProxyInstance建立代理對象 * </ol> */ 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); }
那這個其實很明瞭,註釋上我也已經寫清楚了,再也不贅述。
下面的問題是,代理對象生成了,那切面是如何織入的?
咱們知道InvocationHandler是JDK動態代理的核心,生成的代理對象的方法調用都會委託到InvocationHandler.invoke()方法。而經過JdkDynamicAopProxy的簽名咱們能夠看到這個類其實也實現了InvocationHandler,下面咱們就經過分析這個類中實現的invoke()方法來具體看下Spring AOP是如何織入切面的。
publicObject invoke(Object proxy, Method method, Object[] args) throwsThrowable { MethodInvocation invocation = null; Object oldProxy = null; boolean setProxyContext = false; TargetSource targetSource = this.advised.targetSource; Class targetClass = null; Object target = null; try { //eqauls()方法,具目標對象未實現此方法 if (!this.equalsDefined && AopUtils.isEqualsMethod(method)){ return (equals(args[0])? Boolean.TRUE : Boolean.FALSE); } //hashCode()方法,具目標對象未實現此方法 if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)){ return newInteger(hashCode()); } //Advised接口或者其父接口中定義的方法,直接反射調用,不該用通知 if (!this.advised.opaque &&method.getDeclaringClass().isInterface() &&method.getDeclaringClass().isAssignableFrom(Advised.class)) { // Service invocations onProxyConfig with the proxy config... return AopUtils.invokeJoinpointUsingReflection(this.advised,method, args); } Object retVal = null; if (this.advised.exposeProxy) { // Make invocation available ifnecessary. oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } //得到目標對象的類 target = targetSource.getTarget(); if (target != null) { targetClass = target.getClass(); } //獲取能夠應用到此方法上的Interceptor列表 List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method,targetClass); //若是沒有能夠應用到此方法的通知(Interceptor),此直接反射調用 method.invoke(target, args) if (chain.isEmpty()) { retVal = AopUtils.invokeJoinpointUsingReflection(target,method, args); } else { //建立MethodInvocation invocation = newReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); retVal = invocation.proceed(); } // Massage return value if necessary. if (retVal != null && retVal == target &&method.getReturnType().isInstance(proxy) &&!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { // Special case: it returned"this" and the return type of the method // is type-compatible. Notethat we can't help if the target sets // a reference to itself inanother returned object. retVal = proxy; } return retVal; } finally { if (target != null && !targetSource.isStatic()) { // Must have come fromTargetSource. targetSource.releaseTarget(target); } if (setProxyContext) { // Restore old proxy. AopContext.setCurrentProxy(oldProxy); } } }
主流程能夠簡述爲:獲取能夠應用到此方法上的通知鏈(Interceptor Chain),若是有,則應用通知,並執行joinpoint; 若是沒有,則直接反射執行joinpoint。而這裏的關鍵是通知鏈是如何獲取的以及它又是如何執行的,下面逐一分析下。
首先,從上面的代碼能夠看到,通知鏈是經過Advised.getInterceptorsAndDynamicInterceptionAdvice()這個方法來獲取的,咱們來看下這個方法的實現:
public List<Object>getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) { MethodCacheKeycacheKey = 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); } returncached; }
能夠看到實際的獲取工做實際上是由AdvisorChainFactory. getInterceptorsAndDynamicInterceptionAdvice()這個方法來完成的,獲取到的結果會被緩存。
下面來分析下這個方法的實現:
/** * 從提供的配置實例config中獲取advisor列表,遍歷處理這些advisor.若是是IntroductionAdvisor, * 則判斷此Advisor可否應用到目標類targetClass上.若是是PointcutAdvisor,則判斷 * 此Advisor可否應用到目標方法method上.將知足條件的Advisor經過AdvisorAdaptor轉化成Interceptor列表返回. */ publicList getInterceptorsAndDynamicInterceptionAdvice(Advised config, Methodmethod, Class targetClass) { // This is somewhat tricky... we have to process introductions first, // but we need to preserve order in the ultimate list. List interceptorList = new ArrayList(config.getAdvisors().length); //查看是否包含IntroductionAdvisor boolean hasIntroductions = hasMatchingIntroductions(config,targetClass); //這裏實際上註冊一系列AdvisorAdapter,用於將Advisor轉化成MethodInterceptor AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); Advisor[] advisors = config.getAdvisors(); for (int i = 0; i <advisors.length; i++) { Advisor advisor = advisors[i]; if (advisor instanceof PointcutAdvisor) { // Add it conditionally. PointcutAdvisor pointcutAdvisor= (PointcutAdvisor) advisor; if(config.isPreFiltered() ||pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) { //TODO: 這個地方這兩個方法的位置能夠互換下 //將Advisor轉化成Interceptor MethodInterceptor[]interceptors = registry.getInterceptors(advisor); //檢查當前advisor的pointcut是否能夠匹配當前方法 MethodMatcher mm =pointcutAdvisor.getPointcut().getMethodMatcher(); if (MethodMatchers.matches(mm,method, targetClass, hasIntroductions)) { if(mm.isRuntime()) { // Creating a newobject instance in the getInterceptors() method // isn't a problemas we normally cache created chains. for (intj = 0; j < interceptors.length; j++) { interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptors[j],mm)); } } else { interceptorList.addAll(Arrays.asList(interceptors)); } } } } else if (advisor instanceof IntroductionAdvisor){ IntroductionAdvisor ia =(IntroductionAdvisor) advisor; if(config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) { Interceptor[] interceptors= registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } else { Interceptor[] interceptors =registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } return interceptorList; }
這個方法執行完成後,Advised中配置可以應用到鏈接點或者目標類的Advisor所有被轉化成了MethodInterceptor.
接下來咱們再看下獲得的攔截器鏈是怎麼起做用的。
if (chain.isEmpty()) { retVal = AopUtils.invokeJoinpointUsingReflection(target,method, args); } else { //建立MethodInvocation invocation = newReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); retVal = invocation.proceed(); }
從這段代碼能夠看出,若是獲得的攔截器鏈爲空,則直接反射調用目標方法,不然建立MethodInvocation,調用其proceed方法,觸發攔截器鏈的執行,來看下具體代碼
public Object proceed() throws Throwable { // We start with an index of -1and increment early. if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size()- 1) { //若是Interceptor執行完了,則執行joinPoint return invokeJoinpoint(); } Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); //若是要動態匹配joinPoint 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)) { //執行當前Intercetpor returndm.interceptor.invoke(this); } else { //動態匹配失敗時,略過當前Intercetpor,調用下一個Interceptor return proceed(); } } else { // It's an interceptor, so we just invoke it: The pointcutwill have // been evaluated statically before this object was constructed. //執行當前Intercetpor return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }