一、是什么
AOP是Aspect Oriented Programing的簡稱,最初被譯為“面向方面編程”;
AOP通過橫向抽取機制為無法通過縱向繼承體系進行抽象的重復性代碼提供了解決方案。
比如事務的控制我們就可以按照這種方式,但是橫向抽取出來之后,如何將這些獨立的邏輯融合到業務邏輯中完成和原來一樣的業務操作才是關鍵,這也是AOP解決的主要問題。
1.相關的術語
連接點:程序執行的某個特定位置,如類開始初始化前,類初始化后,類某個方法調用前和調用后,方法拋出異常后。一個類或一段程序代碼擁有一些具有邊界性質的特定點,這些
特定點就被稱為連接點。Spring僅支持方法的連接點,即僅能在方法調用前,方法調用后,方法拋出異常時以及方法調用前后這些程序執行點織入增強。
連接點由兩個信息確定:一是用方法表示程序的執行點,二是用相對點表示的方位。
切點:AOP通過切點定位特定連接點。通俗點說:連接點相當於數據庫中的記錄,而切點相當於查詢條件。切點和連接點不是一對一的關系,一個切點可以匹配多個連接點。
增強:織入目標連接點上的一段程序代碼。增強接口:BeforeAdvice AfterReturningAdvice ThrowsAdvice等。
目標對象:
引介:一種特殊的增強,為類添加一些屬性和方法
織入:將增強添加到目標類具體連接點上的過程
三種方式:編譯器織入 類裝載器織入 動態代理織入
代理:
切面:由切點和增強組成,既包括了橫切邏輯的定義,也包括了連接點的定義。
二、.創建增強類
Spring使用增強類定義橫切邏輯,同時由於Spring只支持方法連接點,增強還包括了在方法的哪一點加入橫切碼的方位信息,所以增強既包含橫向邏輯,又包含部分連接點的信息。
1.增強類型
AOP聯盟為增強定義了org.aopalliance.aop.Advice接口,Spring支持5種類型的增強,安裝增強在目標類方法的連接點設置
①:前置增強:org.springframework.aop.BeforeAdvice代表前置增強,因為Spring只支持方法級的增強,所以MethodBeforeAdvice是目前可用的前置增強,表示雜目標方法執行前實施增強而。
②:后置增強:org.springframework.aop.AfterReturningAdvice代表后增強,表示在目標方法執行后實施增強
③:環繞增強:org.aopalliance.intercept.MethodInterceptor代表環繞增強,表示在目標方法前后執行增強
④:異常拋出增強:org.springframework.aop.ThrowsAdvice代表拋出異常增強,表示在目標方法拋出異常后實施增強
⑤:引介增強:org.springframework.aop.IntroductionInterceptor代表引介增強,表示在目標類中添加一些新的方法和屬性
2.前置增強
示例:假設服務生只做兩件事:歡迎顧客和對顧客服務
①定義實體類Waiter.java
1 package com.smart.advice; 2 3 public interface Waiter { 4 void greetTo(String name); 5 6 void serveTo(String name); 7 }
②:普通的服務情況NaiveWaiter.java
1 package com.smart.advice; 2 3 public class NaiveWaiter implements Waiter { 4 5 public void greetTo(String name) { 6 System.out.println("greet to " + name + "..."); 7 } 8 9 public void serveTo(String name) { 10 System.out.println("serving " + name + "..."); 11 } 12 }
③:假設要在服務之前先友好的打招呼GreetingBeforeAdvice.java
1 package com.smart.advice; 2 3 import java.lang.reflect.Method; 4 5 import org.springframework.aop.MethodBeforeAdvice; 6 7 public class GreetingBeforeAdvice implements MethodBeforeAdvice { 8 public void before(Method method, Object[] args, Object obj) throws Throwable { 9 String clientName = (String) args[0]; 10 System.out.println("How are you!Mr." + clientName + "."); 11 } 12 }
BeforeAdvice是前置增強的接口,方法前置增強的MethodBeforeAdvice接口是其子類,Spring目前只提供方法調用的前置增強。這正是定義BeforeAdvice接口存在的意義。MethodBeforeAdvice接口僅定義了唯一的方法
before(Method method, Object[] args, Object obj)
④:進行測試
1 package com.smart.advice; 2 3 import org.springframework.aop.BeforeAdvice; 4 import org.springframework.aop.framework.ProxyFactory; 5 import org.testng.annotations.*; 6 7 public class BeforeAdviceTest { 8 private Waiter target; 9 private BeforeAdvice advice; 10 private ProxyFactory pf; 11 12 @BeforeTest 13 public void init() { 14 target = new NaiveWaiter(); 15 advice = new GreetingBeforeAdvice(); 16 //①Spring提供的代理工廠 17 pf = new ProxyFactory(); 18 // ②設置代理目標 19 pf.setTarget(target); 20 //③為代理目標添加增強 21 pf.addAdvice(advice); 22 } 23 24 @Test 25 public void beforeAdvice() { 26 Waiter proxy = (Waiter) pf.getProxy(); 27 proxy.greetTo("John"); 28 proxy.serveTo("Tom"); 29 } 30 }
⑤:在Spring中配置
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> 6 7 <bean id="greetingAdvice" class="com.smart.advice.GreetingBeforeAdvice" /> 8 <bean id="target" class="com.smart.advice.NaiveWaiter" /> 9 <bean id="waiter" 10 class="org.springframework.aop.framework.ProxyFactoryBean" 11 p:proxyInterfaces="com.smart.advice.Waiter" p:target-ref="target" 12 p:interceptorNames="greetingAdvice"/> 13 </beans>
代碼介紹:target:代理的目標對象
ProxyInterfaces:代理需要實現的接口,可以是多個接口,別名interfaces
interceptorNames:需要植入目標對象的Bean列表,采用bean的名稱指定,這些Bean必須是實現了org.aopalliance.intercept.MethodInterceptor或org.springframeworkwork.aop.Advisor的Bean.配置的順序對應調用的順序
singleton:返回的代理是否是單實例,默認為單實例
optimize:設置為true時,強制使用CGLib代理
proxyTargetClass:是否對類進行代理,設置為true時,使用CGLib代理。
增強測試代碼:
package com.smart.advice;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.testng.annotations.*;
public class SpringAdviceTest {
@Test
public void testAdvice() {
String configPath = "com/smart/advice/beans.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
Waiter waiter = (Waiter) ctx.getBean("waiter");
waiter.greetTo("John");
}
}
3.后置增強
后置增強在目標類方法調用后執行,假設服務生在每次服務后,也需要使用規范的禮貌用語,則使用后置增強來實現。
1 package com.smart.advice; 2 3 import java.lang.reflect.Method; 4 5 import org.springframework.aop.AfterReturningAdvice; 6 7 public class GreetingAfterAdvice implements AfterReturningAdvice { 8 //在目標類方法調用后執行 9 public void afterReturning(Object returnObj, Method method, Object[] args, 10 Object obj) throws Throwable { 11 System.out.println("Please enjoy yourself!"); 12 } 13 }
與前置增強類似,通過實現AfterReturningAdvice來定義后置增強的邏輯
配置:
1 <bean id="greetingAfter" class="com.smart.advice.GreetingAfterAdvice" /> 2 <bean id="target" class="com.smart.advice.NaiveWaiter" /> 3 <bean id="waiter" 4 class="org.springframework.aop.framework.ProxyFactoryBean" 5 p:proxyInterfaces="com.smart.advice.Waiter" p:target-ref="target" 6 p:interceptorNames="greetingBefore,greetingAfter"/>
4.環繞增強
環繞增強允許在目標類方法調用前后織入橫切邏輯,綜合實現了前置,后置增強兩者的功能、
1 package com.smart.advice; 2 3 import org.aopalliance.intercept.MethodInterceptor; 4 import org.aopalliance.intercept.MethodInvocation; 5 6 public class GreetingInterceptor implements MethodInterceptor { 7 8 public Object invoke(MethodInvocation invocation) throws Throwable { 9 Object[] args = invocation.getArguments();//目標方法入參 10 String clientName = (String) args[0]; 11 System.out.println("How are you!Mr." + clientName + "."); 12 13 Object obj = invocation.proceed(); //通過反射機制調用目標方法 14 15 System.out.println("Please enjoy yourself!"); 16 17 return obj; 18 } 19 }
使用配置:
1 <bean id="greetingAround" class="com.smart.advice.GreetingInterceptor" /> 2 <bean id="target" class="com.smart.advice.NaiveWaiter" /> 3 <bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean" 4 p:proxyInterfaces="com.smart.advice.Waiter" p:target-ref="target" 5 p:interceptorNames="greetingAround" />
5.異常拋出增強
異常拋出增強最適合的應用場景是事務管理,當參與事務的某個Dao發生異常時,事務管理器就必須回滾事務
1 package com.smart.advice; 2 3 import com.smart.domain.ViewSpace; 4 5 import java.sql.SQLException; 6 7 public class ViewSpaceService { 8 9 public boolean deleteViewSpace(int spaceId) { 10 11 throw new RuntimeException("運行異常。"); 12 } 13 14 public void updateViewSpace(ViewSpace viewSpace) throws Exception { 15 // do sth... 16 throw new SQLException("數據更新操作異常。"); 17 18 } 19 }
我們通過TransactionManager這個異常拋出增強對業務方法進行增強處理,同意捕捉拋出的異常並回滾事務
1 package com.smart.advice; 2 3 import java.lang.reflect.Method; 4 5 import org.springframework.aop.AfterReturningAdvice; 6 import org.springframework.aop.ThrowsAdvice; 7 8 9 public class TransactionManager implements ThrowsAdvice, AfterReturningAdvice { 10 public void afterReturning(Object returnObj, Method method, Object[] args, 11 Object obj) throws Throwable { 12 returnObj = false; 13 System.out.println("Please enjoy yourself!"); 14 } 15 16 public void afterThrowing(Method method, Object[] args, Object target, 17 Exception ex) throws Throwable { 18 ex = null; 19 System.out.println("-----------"); 20 System.out.println("method:" + method.getName()); 21 //System.out.println("拋出異常:" + ex.getMessage()); 22 System.out.println("成功回滾事務。"); 23 } 24 }
使用配置:
1 <bean id="viewSpaceSer 2 viceTarget" class="com.smart.advice.ViewSpaceService" /> 3 <bean id="transactionManager" class="com.smart.advice.TransactionManager" /> 4 <bean id="viewSpaceService" class="org.springframework.aop.framework.ProxyFactoryBean" 5 p:interceptorNames="transactionManager" 6 p:target-ref="viewSpaceServiceTarget" 7 p:proxyTargetClass="true"/><!--因為ViewSpaceService是類,所以使用CGLib代理-->
三、創建切面
在增強中,增強被織入目標類的所有方法中,如果希望有選擇地織入目標類某些特定的方法中,就需要使用切點進行,目標連接點的定位。
增強提供了連接點方位信息:如織入方法前面、后面等。而切點進一步描述織入哪些類的哪些方法上。
Spring通過org.springframework.aop.Pointcut接口描述切點。PointCut由ClassFilter(定位類)和MethodMatcher(定位方法)構成。
在ClassFilter只定義了matches(Class clazz),其參數代表一個被檢測類,該方法判別被檢測的類是否匹配過濾條件。
Spring支持兩種方法匹配器:靜態方法匹配器和動態方法匹配器。靜態方法匹配器僅對方法名簽名進行匹配,而動態方法匹配器會在運行期檢查方法入參的值。
1.切點類型
靜態方法切點:org.springframework.aop.support.StaticMethodMatcerPointcut是靜態方法切點的抽象基類,默認情況下它匹配所有的類。StaticMethodMatcherPointcut包括兩個主要的子類
分別是NameMatchMethodPointcut和AbstractRegexpMethodPointcut,前者提供簡單字符串匹配方法前面,而后者使用正則表達式匹配方法前面。
動態方法切點:org.springframework.aop.support.DynamicMethodMatcerPointcut是動態方法切點的抽象基類,默認情況下它匹配所有的類,DynamicMethodMatcerPointcut已經過時,
可以使用DefaultPointcutAdvisor和DynamicMethodMatcherPointcut動態方法代替。
注解切點:org.springframework.aop.support.annotation.AnnotationMatchingPointcut實現類表示注解切點。
表達式切點:org.springframework.aop.support.ExpressionPointcut接口主要是為了支持AspectJ切點表達式語法而定義的接口
流程切點:org.springframework.aop.support.ControlFlowPointcut實現類表示控制流程切點。ControlFlowPointcut是一種特殊的切點,它根據程序執行堆棧的信息查看目標方法是否由某一個方法直接或間接發起調用,以此判斷是否為匹配的連接點
復合切點:org.springframework.aop.support.ComposablePointcut實現類是為了創建多個切點而提供的方便操作類,它所有的方法都返回ComposablePointcut類,這樣就可以使用鏈接表達式對切點進行操作
2.切面類型
一般切面:Advisor代表一般切面,僅包含一個Advice,他本身就是一個簡單的切面,只不過他代表的橫切連接點是所有目標類的所有方法。
切點切面:PointcutAdvisor具有切點的切面,包含Advice和Pointcut兩個類,這樣就可以通過類,方法名以及方法方位等信息靈活地定義切面的連接點
引介切面:IntroductionAdvisor引介切面,引介切面是對應引介增強的特殊切面,它應用於類層面上,使用ClassFilter進行定義。
3.靜態普通方法名匹配切面
StaticMethodMatcherPointcutAdvisor代表一個靜態方法匹配切面,它通過StaticMethodMatcherPointcut定義切點,通過類過濾和方法名匹配定義切點。
示例Waiter.java
1 package com.smart.advisor; 2 3 public class Waiter { 4 5 public void greetTo(String name) { 6 System.out.println("waiter greet to " + name + "..."); 7 } 8 9 public void serveTo(String name) { 10 System.out.println("waiter serving " + name + "..."); 11 } 12 }
Seller.java
1 package com.smart.advisor; 2 3 public class Seller { 4 public void greetTo(String name) { 5 System.out.println("seller greet to " + name + "..."); 6 } 7 }
Waiter有兩個方法,分別是greetTo和serveTo,Seller擁有一個和Waiter相同名稱的方法greetTo()。現在我們在Waiter#greetTo()方法調用前織入一個增強,即連接點為Waiter#greetTo()方法調用前的位置
1 package com.smart.advisor; 2 3 import java.lang.reflect.Method; 4 5 import org.springframework.aop.ClassFilter; 6 import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor; 7 8 public class GreetingAdvisor extends StaticMethodMatcherPointcutAdvisor { 9 10 public boolean matches(Method method, Class clazz) { 11 return "greetTo".equals(method.getName());//切點方法名匹配為greetTo 12 } 13 14 public ClassFilter getClassFilter() {//切點類匹配規則:為Waiter的類或子類 15 return new ClassFilter() { 16 public boolean matches(Class clazz) { 17 return Waiter.class.isAssignableFrom(clazz); 18 } 19 }; 20 } 21 }
因為StaticMethodMatcherPointcutAdvisor抽象類唯一需要定義的是matches()方法。在默認情況下,該切面匹配所有的類,這里通過覆蓋getClassFilter()方法,讓他僅匹配Waiter類及其子類
定義前置增強:
1 package com.smart.advisor; 2 3 import java.lang.reflect.Method; 4 5 import org.springframework.aop.MethodBeforeAdvice; 6 7 public class GreetingBeforeAdvice implements MethodBeforeAdvice { 8 9 public void before(Method method, Object[] args, Object obj) throws Throwable { 10 String clientName = (String) args[0]; 11 System.out.println(obj.getClass().getName() + "." + method.getName()); 12 System.out.println("How are you!Mr." + clientName + "."); 13 } 14 }
配置切面:靜態方法匹配切面
1 <bean id="waiterTarget" class="com.smart.advisor.Waiter" /> 2 <bean id="sellerTarget" class="com.smart.advisor.Seller" /> 3 <bean id="greetingAdvice" class="com.smart.advisor.GreetingBeforeAdvice" /> 4 <bean id="greetingAdvisor" class="com.smart.advisor.GreetingAdvisor" 5 p:advice-ref="greetingAdvice" /><!--向切面注入一個前置增強--> 6 <bean id="parent" abstract="true"<!--通過一個父<bean>定義公共的配置信息--> 7 class="org.springframework.aop.framework.ProxyFactoryBean" 8 p:interceptorNames="greetingAdvisor" p:proxyTargetClass="true" /> 9 <bean id="waiter" parent="parent" p:target-ref="waiterTarget" /><!--waiter代理--> 10 <bean id="seller" parent="parent" p:target-ref="sellerTarget" /><!--seller代理-->
4.靜態正則表達式匹配切面
在上面的配置中只能通過方法名定義切點,這種方式不夠靈活。RegexpMethodPointcutAdvisor是正則表達式方法匹配的切面實現類。
使用正則表達式定義切面:
1 <!-- 正則表達式方法名匹配切面 --> 2 <bean id="regexpAdvisor" 3 class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" 4 p:advice-ref="greetingAdvice"> 5 <property name="patterns"><!--用正則表達式定義目標類全限定方法名的匹配模式串--> 6 <list> 7 <value>.*greet.*</value><!--匹配模式串--> 8 </list> 9 </property> 10 </bean> 11 <bean id="waiter1" class="org.springframework.aop.framework.ProxyFactoryBean" 12 p:interceptorNames="regexpAdvisor" p:target-ref="waiterTarget" 13 p:proxyTargetClass="true" />
四、自動創建代理
在之前的示例中,都是通過ProxtFactoryBean創建織入切面的代理,每一個需要被代理的Bean都需要使用一個ProxyFactoryBean進行配置。
Spring提供了自動代理機制,讓容器自動生成代理。
1.實現類介紹
這些機遇BeanPostProcessor的自動代理創建器的實現類,將根據一些規則自動在容器實例化Bean時為匹配的Bean生成代理實例可以分為3類。
①:基於Bean配置名規則的自動代理創建器:允許為一組特定配置名的Bean自動創建代理實例的創建器,實現類為BeanNameAutoProxyCreator
②:基於Advisor匹配機制的自動代理創建器:會對容器中所有的Advisor進行掃描,自動將這些切面應用到匹配的Bean中,實現類為DefaultAdvisorAutoProxyCreator
③:基於Bean中AspectJ注解標簽的自動代理創建器:為包含AspectJ注解的Bean自動創建代理實例,她的實現類是AnnotationAwareAspectJAutoProxyCreator.
2.BeanNameAutoProxyCreator
1 <bean id="waiter" class="com.smart.advisor.Waiter" /> 2 <bean id="seller" class="com.smart.advisor.Seller" /> 3 <bean id="greetingAdvice" class="com.smart.advisor.GreetingBeforeAdvice" /> 4 <!-- 通過Bean名稱自動創建代理 --> 5 <bean 6 class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator" 7 p:beanNames="*er" p:interceptorNames="greetingAdvice" 8 p:optimize="true"/>
3.DefaultAdvisorAutoProxyCreator
1 <bean id="waiter" class="com.smart.advisor.Waiter" /> 2 <bean id="seller" class="com.smart.advisor.Seller" /> 3 <bean id="greetingAdvice" class="com.smart.advisor.GreetingBeforeAdvice" /> 4 <!--通過Advisor自動創建代理--> 5 <bean id="regexpAdvisor" 6 class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" 7 p:patterns=".*greet.*" p:advice-ref="greetingAdvice" /> 8 <bean 9 class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />
五、基於@AspectJ配置切面
之前是使用Pointcut和Advice接口描述切點和增強,並用Advisor整合兩者描述切面,@AspectJ則采用注解來描述切點,增強,兩者只是表達方式不同。
1、語法基礎
①方法切點函數:通過描述目標類方法信息定義連接點
②:方法入參切點函數:通過描述目標類方法入參的信息定義連接點
③:目標類切點函數:通過描述目標類型信息定義連接點
④:代理類切點函數:通過描述目標類的代理類的信息定義連接點
2、使用准備
在使用之前,要將Spring中的asm模塊添加到類路徑中。
3、編程式織入示例:
1 package com.smart; 2 3 import com.smart.anno.Monitorable; 4 import com.smart.anno.NeedTest; 5 6 @Monitorable 7 public class NaiveWaiter implements Waiter { 8 public void greetTo(String clientName) { 9 System.out.println("NaiveWaiter:greet to "+clientName+"..."); 10 } 11 @NeedTest 12 public void serveTo(String clientName){ 13 System.out.println("NaiveWaiter:serving "+clientName+"..."); 14 } 15 public void smile(String clientName,int times){ 16 System.out.println("NaiveWaiter:smile to "+clientName+ times+"times..."); 17 } 18 }
PreGreetingAspect.java
1 package com.smart.aspectj.example; 2 3 import org.aspectj.lang.annotation.Aspect; 4 import org.aspectj.lang.annotation.Before; 5 @Aspect//通過該注解將PreGreetingAspect標識為一個切面 6 public class PreGreetingAspect{ 7 @Before("execution(* greetTo(..))")//定義切點和增強類型 8 public void beforeGreeting(){//增強的橫切邏輯 9 System.out.println("How are you"); 10 } 11 }
注釋:在類定義處標記了@AspectJ注解,第三方處理程序就可以通過類是否擁有@AspectJ注解判斷是否為一個切面
在beforeGreeting()方法處標記了@Before注解,並為該注解提供了成員值exection(*greetTo(..))、@Before注解表示該增強是一個前置增強,而成員值是一個@AspectJ切點表達式,意思是在目標類greetTo()方法織入增強,greetTo()方法可以帶任意的入參和任意的返回值
beforeGreeting()是增強所使用的橫切邏輯,該橫切邏輯在目標方法前調用
PreGreetingAspect類通過注解和代碼,將切點,增強類型和增強的橫切邏輯整合到一個類中,時切面的定義渾然天成。PreGreetingAspect一個類就相當於之前的BeforeAdvice、N俺么MatchMethodPointcut以及DefaultPointcutAdvisor三者聯合表達的信息
4、通過配置使用@AspectJ切面
① 普通方式
1 <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/> 2 <bean id="waiter" class="com.smart.NaiveWaiter" /> 3 <bean class="com.smart.aspectj.example.PreGreetingAspect" />
② 使用Schema的aop命名空間
1 <aop:aspectj-autoproxy/> 2 <bean id="waiter" class="com.smart.NaiveWaiter" /> 3 <bean class="com.smart.aspectj.example.PreGreetingAspect" />
5、不同增強類型
@Before表示前置增強,相當於BeforeAdvice的功能
value:該成員用於定義切點
argName:由於無法通過Java反射機制獲取方法入參名,所以如果在java編譯時未啟用調試信息或者需要在運行期解析切點,就必須通過這個成員指定注解所標注增強方法的參數名,,多個參數名用逗號分隔
@AfterReturning表示后置增強 相當於AfterReturningAdvice
value:該成員用於定義切點
pointcut:表示切點的信息,如果顯示指定pointcut值,他將覆蓋value的設置值,可以講pointcut成員看成是value的同義詞
returning:將目標對象方法的返回值綁定給增強的方法
argName:同上
@Around:表示環繞增強,相當於MethodInterceptor
value:定義切點
argNames:同上
@AfterThrowing:表示拋出增強相當於ThrowsAdvice
value:定義切點
pointcut:表示切點的信息,如果顯示指定pointcut值,他將覆蓋value的設置值,可以將pointcut成員看成是value的同義詞
throwing:將拋出的異常綁定到增強方法中
argNames:同上
@After 表示final增強,都會執行
value定義切點
argNames同上
@DeclareParents
表示引介增強,相當於IntroductionInterceptor
value:該成員用於定義切點,他表示在哪個目標類上添加引介增強
defaultImpl:默認的接口實現類
總結:AOP是OOP的有益補充,它為程序開發提供了一個嶄新的思考角度,可以將任意性的橫切邏輯抽取到同意的模塊中,只有通過OOP的縱向抽象和AOP的橫向抽取,程序才可以真正解決重復性代碼的問題
Spring采用JDK動態代理和CGLib動態代理的技術在運行期織入增強,左移用戶不需要裝備特殊的編譯器或類裝載器就可以使用AOP的功能,要使用JDK動態代理,目標類必須事先接口,而CGLib不對類做任何限制,通過動態生成目標子類的方式提供代理。
JDK在創建代理對象時性能高於CGLib,而生成的代理對象的運行性能卻比CGLib低,如果是singleton的代理,推薦使用CGLib動態代理
Spring只能在方法級別上織入增強,Spring提供了4中類型的方法增強,分別是前置增強后置增強環繞增強和異常拋出增強此外還有引介增強,引介增強是類級別的
它為目標類織入新的接口實現。廣義上來看,增強其實就是一種最簡單的切面,他既包括橫切代碼也包括切點信息,只不過他的切點只是簡單地方法相對位置的信息,所以增強一般需要和切點聯合才可以表示一個更具有實用性的切面