之前提到的五大增强是被织入目标类的所有方法中。
但如果想选择性增强(织入某些类的某些方法上),则要借助于切点。
spring 主要通过org.springframework.aop.Pointcut 来描述切点
Pointcut接口定义
public interface Pointcut {
/**
* Return the ClassFilter for this pointcut.
* @return the ClassFilter (never <code>null</code>)
*/
ClassFilter getClassFilter();
/**
* Return the MethodMatcher for this pointcut.
* @return the MethodMatcher (never <code>null</code>)
*/
MethodMatcher getMethodMatcher();
/**
* Canonical Pointcut instance that always matches.
*/
Pointcut TRUE = TruePointcut.INSTANCE;
}
PointCut主要依赖于ClassFilter和MethodMatcher,通过
ClassFilter可以定位到某些特定类中,通过MethodMatcher可以定位到某些具体方法。
切面:由切点和增强代码两部分组成。
spring用org.springframework.aop.Advisor表示切面。切面分三类:一般切面、切点切面、引介切面。
1. Advisor:表示一般的切面,仅依赖一个增强接口Advice,作用于目标类的所有方法,使用较少
2. PointcutAdvisor:表示具有切点的切面。包含了增强部分(Advice)和切点(Pointcut),可以灵活的针对某些特定的类、方法增强。
3. IntroductionAdvisor:对应引介增强的特殊的切面。
其中第2点的PointcutAdvisor使用场景最多,我们看下它的子类结构
a)DefaultPointcutAdvisor,通过任意Pointcut和Advice定义一个切面,不支持引介的切面类型,可以通过扩展子类实现自定义的切面
b)NameMatchMethodPointcutAdvisor,按方法名定义切点的切面
c)RegexpMethodPointcutAdvisor,按正则表达式匹配方法名进行切点定义的切面
d)AspectJExpressionPointcutAdvisor,用AspectJ切点表达式定义切点的切面
e)AspectJPointcutAdvisor,用AspectJ语法定义切点的切面
f)StaticMethodMatcherPointcutAdvisor,静态方法匹配器切点定义的切面,默认匹配所有的目标类
例子:
Seller.java
package tome.sample.Advisor;
/**
* 类Seller.java的实现描述:TODO 类实现描述
*
* @author onlyone 2013-4-13 下午08:41:36
*/
public class Seller {
public void greetTo(String name) {
System.out.println("seller greet to " + name + "!");
}
}
Waiter.java
package tome.sample.Advisor;
/**
* 类Waiter.java的实现描述:TODO 类实现描述
*
* @author onlyone 2013-4-13 下午08:41:44
*/
public class Waiter {
public void greetTo(String name) {
System.out.println("waiter greet to " + name + "!");
}
public void serveTo(String name) {
System.out.println("waiter serving " + name + "!");
}
}
package tome.sample.Advisor;
import java.lang.reflect.Method;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;
/**
* 自定义切面
*
* @author onlyone 2013-4-13 下午08:42:10
*/
public class GreetingAdvisor extends StaticMethodMatcherPointcutAdvisor {
/**
* 匹配greetTo方法
*/
public boolean matches(Method method, Class clazz) {
return "greetTo".equals(method.getName());
}
/**
* 匹配Waiter及其子类
*/
public ClassFilter getClassFilter() {
return new ClassFilter() {
public boolean matches(Class clazz) {
return Waiter.class.isAssignableFrom(clazz);
}
};
}
}
前置增强GreetingBeforeAdvice.java
package tome.sample.Advisor;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
/**
* 前置增强
*
* @author onlyone 2013-4-13 下午08:49:02
*/
public class GreetingBeforeAdvice implements MethodBeforeAdvice {
public void before(Method method, Object[] args, Object obj) throws Throwable {
String clientName = (String) args[0];
System.out.println("-----------begin---------------");
System.out.println("GreetingBeforeAdvice is successfully called! "+obj.getClass().getName() + "." + method.getName());
System.out.println("How are you!" + clientName + "!");
System.out.println("-----------end---------------");
}
}
xml配置文件
<?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:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<!-- 普通方法名匹配切面 -->
<bean id="waiterTarget" class="tome.sample.Advisor.Waiter" />
<bean id="sellerTarget" class="tome.sample.Advisor.Seller" />
<bean id="greetingAdvice" class="tome.sample.Advisor.GreetingBeforeAdvice" />
<bean id="greetingAdvisor" class="tome.sample.Advisor.GreetingAdvisor">
<property name="advice" ref="greetingAdvice" />
</bean>
<bean id="parent" abstract="true"
class="org.springframework.aop.framework.ProxyFactoryBean"
p:interceptorNames="greetingAdvisor" p:proxyTargetClass="true" />
<bean id="waiter" parent="parent">
<property name="target" ref="waiterTarget" />
</bean>
<bean id="seller" parent="parent">
<property name="target" ref="sellerTarget" />
</bean>
</beans>
测试类
package tome.sample.Advisor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 测试类
*
* @author onlyone 2013-4-13 下午08:59:36
*/
public class TestAdvisor {
public static void main(String[] args) {
String configPath = "beans.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
Waiter waiter = (Waiter) ctx.getBean("waiter");
Seller seller = (Seller) ctx.getBean("seller");
waiter.greetTo("Tom");
waiter.serveTo("Tom");
seller.greetTo("Tom");
}
}
运行结果:
-----------begin---------------
GreetingBeforeAdvice is successfully called! tome.sample.Advisor.Waiter.greetTo
How are you!Tom!
-----------end---------------
waiter greet to Tom!
waiter serving Tom!
seller greet to Tom!