前文提到了一個切面(Aspect)由切點(Pointcut)和加強(Advice)組成,切點提供了鏈接點的具體類的具體方法信息,而加強提供了橫切代碼以及其織入方法的位子,當單獨使用加強時,會默認的做用於類的全部方法上,想要指定特定的方法就須要切點的使用了,下面進行切點的講解,加強請看上一篇筆記。
java
Spring經過org.springframwork.aop.Pointcut接口描述切點,Pointcut由ClassFilter和MethodMatcher構成,經過ClassFilter對位具體的類,經過Methodmatcher定位方法。Spring支持兩種方法匹配器:靜態方法匹配器和動態方法匹配器,方法匹配器的類型以isRuntime()返回值決定,false爲靜態。
正則表達式
Spring提供了6種類型的切點:靜態方法切點、動態方法切點、註解切點、表達式切點、流程切點、複合切點
spring
org.springframework.aop.support.StaticMethodMatcherPoint,默認匹配全部類包含兩個主要的子類NameMethodmatcherPoint和AbstractRegexpMatcherPoint從類名就能夠看出,前者是經過簡單字符串匹配方法簽名,後者是經過正則表達式配置方法簽名。
編程
仍是以以前睡覺前要洗漱爲例:ide
package advisor; public class Person { public void sleep() { System.out.println("I am sleeping.....ZZZZ"); } public void work() { System.out.println("I am working...."); } }
咱們只但願在sleep方法的前面加上洗漱而不影響work,使用前置加強:性能
package advice; import org.springframework.aop.MethodBeforeAdvice; import java.lang.reflect.Method; public class GreetingBeforeAdvice implements MethodBeforeAdvice { @Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("I am washing face....."); } }
使用靜態方法切點:
測試
public class GreetingAdvisor extends StaticMethodMatcherPointcutAdvisor { @Override public boolean matches(Method method, Class<?> targetClass) { return "sleep".equals(method.getName()); } @Override public ClassFilter getClassFilter() { return new ClassFilter() { @Override public boolean matches(Class<?> clazz) { return Person.class.isAssignableFrom(clazz); } }; } }
能夠看到經過重寫matchs方法,和getClassFilter方法咱們只匹配Person類的sleep方法,使用TestNG測試:spa
package advisor; import advice.GreetingBeforeAdvice; import org.springframework.aop.framework.ProxyFactory; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; public class GreetingAdvisorTest { private ProxyFactory pf; private Person person; private GreetingAdvisor advisor; private GreetingBeforeAdvice advice; @BeforeTest public void init() { person = new Person(); advisor = new GreetingAdvisor(); advice = new GreetingBeforeAdvice(); pf = new ProxyFactory(); advisor.setAdvice(advice); pf.setTarget(person); pf.addAdvisor(advisor); } @Test public void testStaticMethodAdvisor() { person = (Person)pf.getProxy(); person.sleep(); System.out.println("-------------------------------"); person.work(); } }
結果:code
I am washing face..... I am sleeping.....ZZZZ ------------------------------- I am working....
達到了預期目標。regexp
Spring配置文件的配置方式:
...... <bean id="personTarget" class="advisor.Person"/> <bean id="advice" class="advice.GreetingBeforeAdvice"/> <bean id="advisor" class="advisor.GreetingAdvisor" p:advice-ref="advice"/> <bean id="proxyFactory" class="org.springframework.aop.framework.ProxyFactoryBean" abstract="true" p:interceptorNames="advisor" p:proxyTargetClass="true"/> <bean id="person" parent="proxyFactory" p:target-ref="personTarget"/>
初始化ApplicationContext獲取person的實例,便可使用,效果同上
這種方式使用正則表達式去匹配方法的簽名,正則表達式的內容比較多,這裏就不介紹了,使用方式與上面大同小異,只是在匹配方法時不時直接比較字符串,而是用正則表達式匹配,例子相同部分就再也不提。RegexpMethodPointcutAdvisor是正則表達式的切面實現類,該類功能已經齊備,通常狀況下,不須要再繼承重寫他的方法或擴佔方法。
spring配置文件中配置以下:
...... <bean id="personTarget" class="advisor.Person"/> <bean id="advice" class="advice.GreetingBeforeAdvice"/> <bean id="advisor" class="org.springframwork.aop.support.RegexpMethodPointcutAdvisor" p:advice-ref="advice"> <property name="patterns"> <list> <value>.*sleep.*</value> </list> <property> </bean> <bean id="proxyFactory" class="org.springframework.aop.framework.ProxyFactoryBean" abstract="true" p:interceptorNames="advisor" p:proxyTargetClass="true"/> <bean id="person" parent="proxyFactory" p:target-ref="personTarget"/>
直接使用ProxyFactory代碼:
package advisor; import advice.GreetingBeforeAdvice; import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.support.RegexpMethodPointcutAdvisor; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; /** * Created by rex.chen on 14-1-24. */ public class GreetingAdvisorTest { private ProxyFactory pf; private Person person; private GreetingBeforeAdvice advice; private RegexpMethodPointcutAdvisor regexp; @BeforeTest public void init() { person = new Person(); advice = new GreetingBeforeAdvice(); regexp = new RegexpMethodPointcutAdvisor(); pf = new ProxyFactory(); regexp.setAdvice(advice); regexp.setPattern(".*sleep.*"); pf.setTarget(person); pf.addAdvisor(regexp); } @Test public void testStaticMethodAdvisor() { person = (Person)pf.getProxy(); person.sleep(); System.out.println("-------------------------------"); person.work(); } }
org.springframework.aop.support.DynamicMethodMatcherPointcut是動態方法切點的抽象基類,默認狀況下匹配全部的類。動態方法切點與靜態方法切點的區別是前者使用動態方法匹配器,後者使用靜態方法匹配器,區別在於動態方法匹配器會在運行期檢查方法的入參的值來匹配方法,每次調用方法時都將檢查一次入參,因此對性能影響很大,而靜態配置只會匹配一次,因此通常不會用動態方法切點,這裏就不介紹了
org.springframework.aop.support.annotation.AnnotationMatcherPointcut實現類表示註解切點,可使用註解配置切點,後面再詳細介紹
org.springframwork.aop.support.ExpressionPointcut接口主要是爲了支持AspectJ切點表達式語言而定義的接口,後面再詳細介紹
org.springframwork.aop.support.ControlFlowPointcut,根據程序執行的堆棧信息查看目標方法是否由某一個方法直接或間接發起調用,以此判斷是否爲匹配的鏈接點,這裏不詳細介紹。
org.springframwork.aop.support.ComposablePointcut可使用鏈式編程建立多個切點,這裏不詳細介紹。