由于动态切入点除了要考虑方法的名称等静态信息外,还要考虑方法的参数。由于它是动态的,在执行时既要计算方法的静态信息,还要计算其参数,结果也不能被缓存。因此,动态切入点要消耗更多的系统资源。
Spring提供的动态切入点的实现:
ControlFlowPointcut:控制流程切入点。例如只有在某个特定的类或方法中调用某个连接点时,装备才会被触发,这时就可以使用ControlFlowPointcut,但是他的系统开销很大,在追求高效的应用中,不推荐使用。
DynamicMethodMatcherPointcut:动态方法匹配器,是抽象类,扩展该类可以实现自己的动态Pointcut。
如果需要自定义切入点可以通过扩展DynamicMethodMatcherPointcut来实现。
ControlFlowPointcut有两个实现类:
ControlFlowPointcut(Class clazz)指定一个类作为流程切入点
ControlFlowPointcut(Class clazz,String methodName)指定一个类和某一个方法作为流程切入点
在上一节中,People的方法并不是全部需要执行。在PeopleDelegate中定义live()方法,执行speak()、talk()方法
package test.pointcut;
public class PeopleDelegate {
private People people;
public void setPeople(People people) {
this.people = people;
}
public void live() {
people.speak();
people.talk();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<bean id="peopleTarget" class="test.pointcut.People"></bean>
<bean id="peopleAdvice" class="test.pointcut.PeopleBeforeAdvice"></bean>
<bean id="people"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames">
<idref bean="peopleAdvisor" />
</property>
<property name="target" ref="peopleTarget"></property>
</bean>
<bean id="peopleDelegate" class="org.springframework.aop.support.ControlFlowPointcut">
<constructor-arg type="java.lang.Class" value="test.pointcut.PeopleDelegate"></constructor-arg>
<constructor-arg type="java.lang.String" value="live"></constructor-arg>
</bean>
<bean id="peopleAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<!--
<property name="patterns">
<list>
<value>.*k</value>
</list>
</property>-->
<property name="pointcut" ref="peopleDelegate"></property>
<property name="advice" ref="peopleAdvice"></property>
</bean>
</beans>
package test.pointcut;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-servlet2.xml");
People people = (People) context.getBean("people");
people.speak();
people.talk();
people.run();
PeopleDelegate delegate = new PeopleDelegate();
delegate.setPeople(people);
delegate.live();
}
}
运行结果:
People Speaking
People Talk
People Run
People is speak !
People Speaking
People is talk !
People Talk
对于面向切面,代理对象如PeopleDelegate在每次调用目标方法时,都需要判断方法调用堆栈中是否满足流程切点的要求,因此流程切面对性能的影响特别大,在JVM1.4中,流程切点通常比其他切点慢5倍,在jvm1.3中慢10倍。
如果需要自定义动态切入点,可以通过扩展DynamicMethodMatcherPointcut抽象类,将isRuntime方法表示为final并且放回true,这样就创建了一个动态切入点,该抽象类默认匹配所有类和方法,可以通过扩展该类编写符合要求的动态切入点。