AOP的應用場合是受限的,它通常只適合於那些具備橫切邏輯的應用場合:性能檢測,訪問控制、事務管理,日誌記錄等java
AOP是什麼?正則表達式
Aspect Oriented Programming。面向方面編程。spring
一些重複代碼沒法經過縱向繼承(即抽象父類)的方式來消除,AOP提供了一種解決這類沒法經過縱向編程解決的問題的方法,即經過橫向抽取機制。編程
AOP概念性能
①鏈接點(JoinPoint)spa
一個類或一段程序代碼擁有一些具備邊界性質的特定點,這些代碼中的特定點稱爲鏈接點。鏈接點由兩個信息肯定,第一爲用方法表示的程序執行點,第二是用相對點表示的方位。代理
②切點(PointCut)日誌
一個類中有多個鏈接點,如何定位到某一個特定的鏈接點呢?AOP經過切點來定位鏈接點。切點只定位到某個方法上,具體的方位還不能肯定.code
③加強(Advice)regexp
加強是織入到目標類鏈接點上的一段代碼。加強除了用來描述一段程序代碼外,還擁有鏈接點的方位、
只有結合切點和加強纔可以肯定特定的鏈接點並實施加強邏輯。
④目標對象(Target)
加強邏輯的織入目標類
⑤引入(Introduction)
引入是一種特殊的加強。它爲類添加一些屬性和方法。即即便一個業務類沒有實現某個接口,經過AOP的引入功能,能夠動態地爲該業務類添加接口的實例邏輯,讓業務類成爲這個接口的實現類。
⑥織入(Weaving)
織入是將加強添加到目標類具體鏈接點上的過程。AOP由三種織入的方式:編譯器織入,類裝載器織入,動態代理織入。
⑦代理(Proxy)
一個類被AOP織入加強後,就產生一個結果類,它是融合了原類和加強邏輯的代理類。代理類多是與原類實現相同接口的類,也可能就是原類的子類。因此能夠以調用原類相同的方法來調用代理類。
⑧切面(Aspect)
切面由切點和加強組成,它既包括了橫切邏輯的定義,也包括了鏈接點的定義。AOP將切面所定義的橫切邏輯織入到切面定義的鏈接點中。
經過建立加強類的方式來實現AOP
步驟:①首先建立加強類,經過實現某個接口(BeforeAdvice, AfterReturningAdvice, MethodInterceptor, ThrowsAdvice, IntroductionInterceptor)來實現一個加強邏輯類。
②在Spring配置文件中進行配置。首先配置一個Advice Bean和目標對象Bean,而後建立一個代理Bean(ProxyFactoryBean),在代理Bean中配置interfaces。target,advice等等屬性;
③獲得代理Bean,調用業務方法。
①定義一個接口 public interface Waiter { void greetTo(String name); void serveTo(Sring name); } ②實現此接口 public class MyWaiter implements Waiter { public void greetTo(String name){ System.out.println("hello!"+name); } public void serveTo(String name){ System.out.println("serving"+name); } } ③建立加強類 public class GreetingBeforeAdvice implements MethodBeforeAdvice { public void before(Method method, Object[] args, Object obj){ String name = (String) args[0]; System.out.println("before " + name); } } ④配置AOP <bean id="beforeAdvice" class="GreetingBeforeAdvice"/> <bean id="target" class="MyWaiter"/> <bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces" value="Waiter"/> <property name="interceptorNames"> <list> <idref local="beforeAdvice"/> </list> </property> <property name="target" ref="target"/> </bean> ⑤調用業務方法 Waiter waiter = (Waiter) ctx.getBean("waiter"); waiter.greetTo("kaka");
ProxyFactoryBean爲其餘Bean建立代理實例。它的可配置屬性有target、proxyInterfaces、interceptorNames、singleton、optimize。proxyTargetClass(設置爲true是使用CGLib進行代理)
說明:public void before(Method method, Object[] args, Object obj)中method爲要加入加強邏輯的方法,args爲方法入參,obj爲代理目標對象
public void afterReturning(Method method, Object[] args, Object obj)、
Object invoke(MethodInvocation invocation) { Object[] args = invocation.getArguments(); Object resuld = invocation.proceed();}
public void afterThrowing(Method method, Object[] args, Object obj, Exception ex)
比較特殊的一個是引入加強。他不是在目標方法周圍織入加強,而是爲目標類建立新的屬性或方法,因此引入加強的鏈接點是類級別的,而非方法級別的。通常經過擴展DelegatingIntroductionInterceptor類。
定義一個接口 public interface Monitor { void setMonitorActive(boolean active); } 定義一個引入加強類 public class IntroductionAdvice extends DelegatingIntrodutionInterceptor implements Monitor { private ThreadLocal<Boolean> map = new ThreadLocal<>(); public void setMonitorActive(boolean active){ map.set(active); } public Object invoke(MethodInvocation invocation){ Object obj = null; if(map.get()){ begin(); obj = super.invoke(invocation); end(); }else{ obj = super.invoke(invocation); } return obj; } } 配置引入加強 <bean id="introductionAdvice" class="IntroductionAdvice"/> <bean id="target" class="MyWaiter"/> <bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="interfaces" value="...Monitor"/> <property name="interceptorNames"> <list> <idref local="beforeAdvice"/> </list> </property> <property name="target" ref="target"/> <property name="proxyTargetClass" value="true"/> </bean> 調用業務方法 Waiter waiter = (Waiter) ctx.getBean("waiter"); waiter.greetTo("kaka"); Monitor monitor = (Monitor) waiter; monitor.setMonitorActive(true); monitor.greetTo("kaka")
經過建立切面(Aspect)的方式來實現AOP
切面同時包含橫切代碼和鏈接點信息。切面可分爲三類:通常切面,切點切面,引入切面
PointcutAdvisor有6個主要的實現類:DefaultPointcutAdvisor, NameMatchMethodPointcutAdvisor, RegexpMethodPointcutAdvisor, StaticMethodMatcherPointcutAdvisor, AspectJExpressionPointcutAdvisor, AspectJPointcutAdvisor。
①靜態方法名匹配切面
步驟:1)定義目標類; 2)定義切面; 3)定義加強類;4)配置切面;5)運行業務代碼
public class GreetingAdvisor extends StaticMethodMatcherPointcutAdvisor { public bolean matches(Method method, Class clazz){ return "greetTo".equals(method.getName()); } public ClassFilter getClassFilter(){ return new ClassFilter(){ public boolean matches(Class clazz){ return Waiter.class.isAssignable(clazz); } }; } } 配置 <bean id="target" class="MyWaiter"/> <bean id="beforeAdvice" class="GreetingBeforeAdvice"/> <bean id="beforeAdvisor" class="GreetingAdvisor"/> <property name="advisor" ref="beforeAdvice"/> </bean> <bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="interceptorNames"> <list> <idref local="beforeAdvisor"/> </list> </property> <property name="target" ref="target"/> <property name="targetProxyClass" value="true"/> </bean>
②靜態正則表達式方法匹配切面
只需配置便可
<bean id="beforeAdvice" class="GreetingBeforeAdvice"/> <bean id="regexpAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="patterns"> <list> <value>.*greet.*</value> </list> </proerty> <property name="advice" ref="beforeAdvice"/> </bean> <bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="interceptorNames"> <list> <idref local="regexpAdvisor"/> </list> </property> <property name="target" ref="target"/> <property name="targetProxyClass" value="true"/> </bean>
自動建立代理
在前面的例子中,咱們經過PRoxyFactoryBean建立織入切面的代理,但每個須要被代理的Bean都須要一個單獨的PRoxyFactoryBean進行配置,這樣配置非常麻煩。因此Spring引入了自動代理機制,讓容器爲咱們自動生成代理,將咱們從繁瑣的配置工做中解放出來。在內部,Spring用BeanPostProcessor自動的完成這項工做。
①實現類
基於BeanPostProcessor的自動建立器的實現類,將根據一些規則自動的在容器實例化Bean時爲匹配的Bean生成代理實例。
這些代理建立器能夠分爲一下三類:
~根據Bean配置名規則的自動代理建立器,BeanNameAutoProxyCreator
~基於Advisor匹配機制的自動代理建立器 DefaultAdvisorAutoProxyCreator
~基於Bean中AspectJ註解標籤的自動代理建立器 AnnotatiobAwareAspectJAutoProxyCreator
②使用Bean名進行自動代理
<bean id="beforeAdvice" class="GreetingBeforeAdvice"/> <bean id="nameCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="beanNames" value="*er"/> <property name="interceptorNames"> <idref local="beforeAdvice"/> </property> </bean>
③使用Advisor自動代理建立器
由於Advisor切面已經包括了鏈接點信息和橫切邏輯,因此直接而配置一自動代理建立器便可
<bean id="beforeAdvice" class="GreetingBeforeAdvice"/> <bean id="regexpAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="patterns"> <list> <value>.*greet.*</value> </list> </proerty> <property name="advice" ref="beforeAdvice"/> </bean> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>