基于Schema的AOP从Spring2.0之后通过“aop”命名空间来定义切面、切入点及声明通知。
在Spring配置文件中,所以AOP相关定义必须放在<aop:config>标签下,该标签下可以有<aop:pointcut>、<aop:advisor>、<aop:aspect>标签,配置顺序不可变。
<aop:pointcut>:用来定义切入点,该切入点可以重用
<aop:advisor>:用来定义只有一个通知和一个切入点的切面;
<aop:aspect>:用来定义切面,该切面可以包含多个切入点和通知,而且标签内部的通知和切入点定义是无序的;和advisor的区别就在此,advisor只包含一个通知和一个切入点。
标签 | 说明 |
---|---|
<aop:config> | AOP定义开始 |
<aop:pointcut/> | 切入点定义 |
<aop:advisor advice-ref=""/> | Advisor定义(零个或多个) |
<aop:aspect ref="aspect"> | 切面定义开始,无序 |
<aop:pointcut expression="" id=""/> | 切入点定义 |
<aop:before/> | 前置通知 |
<aop:after/> | 后置通知 |
<aop:after-returning/> | 后置返回通知 |
<aop:after-throwing> | 后置异常通知 |
<aop:after/> | 后置最终通知 |
<aop:around/> | 环绕通知 |
< <aop:declare-parents/> | 引入定义 |
</aop:aspect> | 切面定义 |
</aop:config> | AOP定义结束 |
一.声明切面
切面就是包含切入点和通知的对象,在Spring容器中将被定义为一个Bean,Schema方式的切面需要一个切面支持Bean,该支持Bean的字段和方法提供了切面的状态和行为信息,并通过配置方式来指定切入点和通知实现。
切面使用<aop:aspect>标签指定,ref属性用来引用切面支持Bean。
切面支持Bean“aspectSupportBean”跟普通Bean完全一样使用,切面使用“ref”属性引用它
二.声明切入点
切入点在Spring中也是一个Bean,Bean定义方式可以有很三种方式:
<b>(1).</b>在<aop:config>标签下使用<aop:pointcut>声明一个切入点Bean,该切入点可以被多个切面使用,对于需要共享使用的切入点最好使用该方式,该切入点使用id属性指定Bean名字,在通知定义时使用pointcut-ref属性通过该id引用切入点,expression属性指定切入点表达式:
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* cn.zlb.*.*(..))"/>
<aop:aspect ref="aspectSupportBean">
<aop:before pointcut-ref="pointcut" method="before"/>
</aop:aspect>
</aop:config>
<b>(2).</b>在<aop:aspect>标签下使用<aop:pointcut>声明一个切入点Bean,该切入点可以被多个切面使用,但一般该切入点只被该切面使用,当然也可以被其他切面使用,但最好不要那样使用,该切入点使用id属性指定Bean名字,在通知定义时使用pointcut-ref属性通过该id引用切入点,expression属性指定切入点表达式:
<aop:config>
<aop:aspect ref="aspectSupportBean">
<aop:pointcut id=" pointcut" expression="execution(* cn.zlb.*.*(..))"/>
<aop:before pointcut-ref="pointcut" method="before"/>
</aop:aspect>
</aop:config>
<b>(3).</b>匿名切入点Bean,可以在声明通知时通过pointcut属性指定切入点表达式,该切入点是匿名切入点,只被该通知使用:
<aop:config>
<aop:aspect ref="aspectSupportBean">
<aop:after pointcut="execution(* cn.zlb.*.*(..))" method="afterFinallyAdvice"/>
</aop:aspect>
</aop:config>
三.声明通知
-
前置通知
在切入点选择的方法之前执行,通过<aop:aspect>标签下的<aop:before>标签声明
<b>pointcut</b>和:<b>pointcut-ref</b>二者选一,指定切入点;<b>method:</b>指定前置通知实现方法名,如果是多态需要加上参数类型,多个用“,”隔开,如beforeAdvice(java.lang.String);
<b>arg-names:</b>指定通知实现方法的参数名字,多个用“,”分隔,可选,
接口:
public interface IHelloWorldService {
public void sayBefore(String name);
}
实现类:
public class HelloWorldService implements IHelloWorldService{
@Override
public void sayBefore(String name) {
System.out.println("============Hello World!"+name);
}
}
定义通知实现:
//前置通知
public void beforeAdvice(String name) {
System.out.println("===========before advice param:"+name);
}
xml配置:
<bean id="helloWorldService" class="com.zlb.service.imp.HelloWorldService"/>
<bean id="aspect" class="com.zlb.aop.HelloWorldAspect"/>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.zlb.service.*.*(..))"/>
<aop:aspect ref="aspect">
<aop:before pointcut="execution(* com.zlb.service.imp.HelloWorldService.sayBefore(..)) and args(name)" method="beforeAdvice(java.lang.String)" arg-names="name"/>
</aop:aspect>
</aop:config>
- 后置返回通知
pointcut和pointcut-ref:同前置通知同义;
method:同前置通知同义;
arg-names:同前置通知同义;
returning:定义一个名字,该名字用于匹配通知实现方法的一个参数名,当目标方法执行正常返回后,将把目标方法返回值传给通知方法;returning限定了只有目标方法返回值匹配与通知方法相应参数类型时才能执行后置返回通知,否则不执行,对于returning对应的通知方法参数为Object类型将匹配任何目标返回值
接口:
public interface IHelloWorldService {
public boolean sayAfter(Object obj);
}
实现类:
public class HelloWorldService implements IHelloWorldService{
@Override
public boolean sayAfter(Object obj) {
return false;
}
}
定义通知实现:
//后置最终通知
public void afterFinallyAdvice(Object obj) {
System.out.println("===========after finally advice param:"+obj);
}
xml配置:
<bean id="helloWorldService" class="com.zlb.service.imp.HelloWorldService"/>
<bean id="aspect" class="com.zlb.aop.HelloWorldAspect"/>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.zlb.service.*.*(..))"/>
<aop:aspect ref="aspect">
<aop:after-returning pointcut="execution(* com.zlb.service.imp.HelloWorldService.sayAfter(..))" method="afterFinallyAdvice" arg-names="obj" returning="obj"/>
</aop:aspect>
</aop:config>
- 后置异常通知
pointcut和pointcut-ref:同前置通知同义;
method:同前置通知同义;
arg-names:同前置通知同义;
throwing:定义一个名字,该名字用于匹配通知实现方法的一个参数名,当目标方法抛出异常返回后,将把目标方法抛出的异常传给通知方法;throwing限定了只有目标方法抛出的异常匹配与通知方法相应参数异常类型时才能执行后置异常通知,否则不执行,对于throwing对应的通知方法参数为Throwable类型将匹配任何异常。
接口:
public interface IHelloWorldService {
public void sayAfterThrowing();
}
实现类:
public class HelloWorldService implements IHelloWorldService{
@Override
public void sayAfterThrowing() {
System.out.println("============before throwing");
throw new RuntimeException();
}
}
定义通知实现:
//异常通知
public void afterThrowingAdvice(Exception exception) {
System.out.println("===========after throwing advice exception:" + exception);
}
xml配置:
<bean id="helloWorldService" class="com.zlb.service.imp.HelloWorldService"/>
<bean id="aspect" class="com.zlb.aop.HelloWorldAspect"/>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.zlb.service.*.*(..))"/>
<aop:aspect ref="aspect">
<aop:after-throwing pointcut="execution(* com.zlb.service.imp.HelloWorldService.sayAfterThrowing(..))" method="afterThrowingAdvice" arg-names="exception" throwing="exception"/>
</aop:aspect>
</aop:config>
- 后置最终通知
pointcut和pointcut-ref:同前置通知同义;
method:同前置通知同义;
arg-names:同前置通知同义
接口:
public interface IHelloWorldService {
public void sayAfterFinally();
}
实现类:
public class HelloWorldService implements IHelloWorldService{
@Override
public void sayAfterFinally() {
System.out.println("============before finally");
throw new RuntimeException();
}
}
定义通知实现:
//最终通知
public void afterFinallyAdvice() {
System.out.println("===========after finally advice");
}
xml配置:
<bean id="helloWorldService" class="com.zlb.service.imp.HelloWorldService"/>
<bean id="aspect" class="com.zlb.aop.HelloWorldAspect"/>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.zlb.service.*.*(..))"/>
<aop:aspect ref="aspect">
<aop:after pointcut="execution(* com.zlb.service.imp.HelloWorldService.sayAfterFinally(..))" method="afterFinallyAdvice"/>
</aop:aspect>
</aop:config>
- 环绕通知
环绕着在切入点选择的连接点处的方法所执行的通知,环绕通知非常强大,可以决定目标方法是否执行,什么时候执行,执行时是否需要替换方法参数,执行完毕是否需要替换返回值,可通过<aop:aspect>标签下的<aop:around >标签声明
接口:
public interface IHelloWorldService {
public void sayAround(String param);
}
实现类:
public class HelloWorldService implements IHelloWorldService{
@Override
public void sayAround(String param) {
System.out.println("============around param:" + param);
}
}
定义通知实现:
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("===========around before advice");
Object retVal = pjp.proceed(new Object[] {"replace"});
System.out.println("===========around after advice");
return retVal;
}
xml配置:
<bean id="helloWorldService" class="com.zlb.service.imp.HelloWorldService"/>
<bean id="aspect" class="com.zlb.aop.HelloWorldAspect"/>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.zlb.service.*.*(..))"/>
<aop:aspect ref="aspect">
<aop:around pointcut="execution(* com.zlb.service.imp.HelloWorldService.sayAround(..))" method="aroundAdvice"/>
</aop:aspect>
</aop:config>
网友评论