您的位置:首页 > 编程语言 > Java开发

精通Spring 4.x企业应用开发实战——AOP(七②)

2018-03-19 13:43 567 查看
创建切面
Spring通过org.springframework.aop.Pointcut接口描述切点。



Pointcut由ClassFilter和MethodMatcher构成,ClassFilter负责定位某些特定的类上,MethodMatcher定位到某些特定的方法上。
切点类型
1、静态方法切点:StaticMethodMatcherPointcut包含NameMethodMatchPointcut和AbstractRegexpMethodPointcut两个方法,前者提供字符串匹配方法签名后者提供正则表达式匹配方法签名。
2、动态方法切点:
3、注解切点:
4、表达式切点:
5、流程切点:
6、复合切点:
切面类型:切面可以分为三类:一般切面、切点切面和引介切面
Advisor:一般切面,仅包含一个Advice,因为Advice包含了横切代码和连接点信息,所以Advice本身就是一个简单的切面。
PointcutAdvisor:具有切点的切面,包含Advice和Pointcut两个类,这样就可以通过类、方法名和方法方位等信息定义切面的连接点。



IntroductionAdvisor:引介切面,是对引介增强的特殊切面,应用于类层面上,所以引介切点使用ClassFilter进行定义。

PointcutAdvisor主要实现类体系:



PointcutAdvisor的6个主要实现类:
DefaultPointcutAdvisor:最常用的切面类型,可以通过任意Pointcut和Advice定义一个切面,唯一不支持的是引介的切面类型。
NameMatchMethodPointcAdvisor:通过该类可以通过扩展该类实现自定义的切面。
RegexpMethodPointcutAdvisor:按正则表达式匹配方法名进行切点定义的切面,可以通过扩展该实现类进行操作。
StaticMethodMatcherPointcutAdvisor:静态方法匹配器切点定义的切面,默认情况下匹配所有的目标类。
AspectJExpressionPointcutAdvisor: 用于AspectJ切点表达式定义切点的切面。
AspectJPointcutAdvisor:用于AspectJ语法定义切点的切面。

静态普通方法名匹配切面:

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 to "+name+"...");
}
}
public class Seller {
public void greetTo(String name){
System.out.println("seller greet to "+name+"...");
}
}
public class GreetingAdvisor extends StaticMethodMatcherPointcutAdvisor{
/**
*切点方法匹配规则:方法名为greetTo
*/
public boolean matches(Method method, Class aClass) {
return "greetTo".equals(method.getName());
}
/**
* 切点的匹配规则:为Waiter的类或者子类
*/
@Override
public ClassFilter getClassFilter() {
return new ClassFilter() {
public boolean matches(Class<?> aClass) {
return Waiter.class.isAssignableFrom(aClass);
}
};
}
}
增强类
public class GreetingBeforeAdvice implements MethodBeforeAdvice {
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println(o.getClass().getName()+"."+method.getName());
String clientName = (String) objects[0];
System.out.println("How are you! Mr."+clientName+".");
}
}
配置切面:静态方法匹配切面
<bean id="waiterTarget" class="Advisor.Waiter"/>
<bean id="sellerTarget" class="Advisor.Seller"/>
<bean id="greetingAdvice" class="Advisor.GreetingBeforeAdvice"/>
<bean id="greetingAdvisor" class="Advisor.GreetingAdvisor"
p:advice-ref="greetingAdvice"/><!--向切面注入一个前置增强-->

<!--通过父Bean定义公共的配置信息-->
<bean id="parent" abstract="true"
class="org.springframework.aop.framework.ProxyFactoryBean"
p:interceptorNames="greetingAdvisor"
p:proxyTargetClass="true"/>

<!--waiter和seller代理-->
<bean id="waiter" parent="parent" p:target-ref="waiterTarget"/>
<bean id="seller" parent="parent" p:target-ref="sellerTarget"/>
测试
@Test
public void test(){
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("AdvisorBeans.xml");
Waiter waiter = (Waiter) applicationContext.getBean("waiter");
Seller seller = (Seller) applicationContext.getBean("seller");

waiter.greetTo("John");
waiter.serveTo("Jbs");
seller.greetTo("yax");

}静态正则表达式方法匹配切面
配置信息:
<bean id="regexpAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"
p:advice-ref="greetingAdvice">
<property name="patterns"><!--用正则表达式定义目标类全限定方法名的匹配模式串-->
<list>
<value>.*greet.*</value><!--匹配模式串-->
</list>
</property>
</bean>
<bean id="waiter1" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interceptorNames="regexpAdvisor"
p:target-ref="waiterTarget"
p:proxyTargetClass="true"/>动态切面
public class GreetingDynamicPointcut extends DynamicMethodMatcherPointcut {

private static List<String> specialList = new ArrayList<String>();
static {
specialList.add("John");
specialList.add("yax");
}

/**
*对类进行静态切点检查
*/
@Override
public ClassFilter getClassFilter() {
return new ClassFilter(){
public boolean matches(Class aClass) {
System.out.println("调用getClassFilter()对"+aClass.getName()+"做静态检查");
return Waiter.class.isAssignableFrom(aClass);
}
};
}
/**
*对方法进行静态切点检查
*/
@Override
public boolean matches(Method method, Class<?> clazz) {
System.out.println("调用matches(method,clazz)"+clazz.getName()+"."+method.getName()+"做静态检查");
return "greetTo".equals(method.getName());
}

/**
*对方法进行动态切点检查
*/
public boolean matches(Method method, Class<?> clazz, Object[] args) {
System.out.println("调用matches(method,clazz)"+clazz.getName()+"."+method.getName()+"做动态检查");
String clientName = (String) args[0];
return specialList.contains(clientName);
}
}
<!--动态切面配置-->
<bean id="waiterTarget1" class="Advisor.Waiter"/>
<bean id="dynamicAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut">
<bean class="Advisor.GreetingDynamicPointcut"/>
</property>
<property name="advice">
<bean class="Advisor.GreetingBeforeAdvice"/>
</property>
</bean>
<bean id="waiter2" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interceptorNames="dynamicAdvisor"
p:target-ref="waiterTarget1"
p:proxyTargetClass="true"/>

流程切面
Spring的流程切面是由DefaultPointcutAdvisor和ControlFlowPointcut实现。
流程切点代表某个方法直接或者间接发起调用其他方法。
实例:
    public class WaiterDelegate {
private Waiter waiter;
/**
*waiter的方法通过该方法发起调用
*/
public void service(String clientName){
waiter.serveTo(clientName);
waiter.serveTo(clientName);
}

public void setWaiter(Waiter waiter) {
this.waiter = waiter;
}
}
配置控制流程切面:
<!--配置控制流程切面-->
<bean id="greetingAdvice1" class="Advisor.GreetingBeforeAdvice"/>
<bean id="waiterTarget2" class="Advisor.Waiter"/>
<bean id="controlFlowPointcut" class="org.springframework.aop.support.ControlFlowPointcut">
<constructor-arg type="java.lang.Class" value="Advisor.WaiterDelegate"/><!--指定流程切点的类-->
<constructor-arg type="java.lang.String" value="service"/><!--指定流程切点的方法-->
</bean>
<bean id="controlFlowAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"
p:pointcut-ref="controlFlowPointcut"
p:advice-ref="greetingAdvice1"/>
<bean id="waiter3" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interceptorNames="controlFlowAdvisor"
p:target-ref="waiterTarget2"
p:proxyTargetClass="true"/>复合切点切面:
public class GreetingComposablePointcut {
public Pointcut getIntersectionPointcut(){
//创建一个复合切点
ComposablePointcut cp = new ComposablePointcut();
//创建一个流程切点
Pointcut pt1 = new ControlFlowPointcut(WaiterDelegate.class,"service");
//创建一个方法名切点
NameMatchMethodPointcut pt2 = new NameMatchMethodPointcut();
pt2.addMethodName("greetTo");
//将两个切点进行交集操作
return cp.intersection((Pointcut) pt2).intersection(pt1);
}
}
配置复合切点切面
<!--配置复合切点切面-->
<bean id="greetingAdvice3" class="Advisor.GreetingBeforeAdvice"/>
<bean id="gcp" class="Advisor.GreetingComposablePointcut"/>
<bean id="composableAdvice" class="org.springframework.aop.support.DefaultPointcutAdvisor"
p:pointcut="#{gcp.intersectionPointcut}"
p:advice-ref="greetingAdvice3"/><!--引用gcp.getIntersectionPointcut()方法所返回的复合切点-->
<bean id="waiter4" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interceptorNames="composableAdvice"
p:target-ref="waiterTarget"
p:proxyTargetClass="true"/>引介切面
引介切面是引介增强的封装器
引介切面的继承关系



IntroductionInfo接口描述了目标类需要实现的新接口。IntroductionAdvisor和PointcutAdvisor接口不同,它仅有一个过滤器ClassFilter而没有MethodMatcher,这是因为引介切面的切点是类级别的,而Pointcut的切点是方法级别的。

配置引介切面
<bean id="introduceAdvisor" class="org.springframework.aop.support.DefaultIntroductionAdvisor">
<constructor-arg><!--ControllablePerformanceMonitor是一个Advice对象-->
<bean class="Advice.ControllablePerformanceMonitor"/>
</constructor-arg>
</bean>
<bean id="forumServiceTarget" class="Advice.ForumService"/>
<bean id="forumService" class="org.springframework.aop.framework.ProxyFactoryBean"
p:proxyTargetClass="true"
p:target-ref="forumServiceTarget"
p:interceptorNames="introduceAdvisor"/>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Spring
相关文章推荐