前文提到了一个切面(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可使用链式编程建立多个切点,这里不详细介绍。