转自:Spring入门(Schema-based AOP其三)
<bean id="moocAspect" class="com.imooc.aop.schema.advice.MoocAspect"></bean>
<bean id="aspectBiz" class="com.imooc.aop.schema.advice.biz.AspectBiz"></bean>
<aop:config>
<aop:aspect id="moocAspectAOP" ref="moocAspect">
<aop:pointcut id="moocPiontcut"
expression="execution(* com.imooc.aop.schema.advice.biz.*Biz.*(..))"/>
<!--前置通知-->
<aop:before method="before" pointcut-ref="moocPiontcut"/>
<!--正常返回后通知,可限制返回值returning="retVal,异常则不会返回-->
<aop:after-returning method="afterReturning" pointcut-ref="moocPiontcut"/>
<!--After throwing advice,在抛出异常之后返回;正常情况下不返回-->
<aop:after-throwing method="afterThrowing" pointcut-ref="moocPointcut"/>
<!--After(finally) advice,无论是否异常都会执行finally-->
<aop:after method="after" pointcut-ref="moocPointcut"/>
<!--Around advice 环绕通知 这个通知的方法的第一个参数必须是ProceedingJoinPoint类型-->
<aop:around method="around" pointcut-ref="moocPiontcut"/>
</aop:aspect>
</aop:config>
//MoocAspect被我们声明成了切面类。
public class MoocAspect{
public void before(){
System.out.println("MoocAspect Before.");
}
public void afterReturning(){
System.out.println("MoocAspect afterReturning.");
}
public void afterThrowing(){
System.out.println("MoocAspect afterThrowing.");
}
public void after(){
System.out.println("MoocAspect after.");
}
/*必须有一个参数,第一个参数必须是ProceedingJoinPoint 这种类型,这个类型的参数有一个proceed方法,也就是执行当前业务的方法。
在具体业务执行之前或者之后都可以进行我们想做的事情。
这里考虑这个异常是否要捕捉到并处理,如果不需要可以写为
public Object around(ProceedingJoinPoint pjp) throw Throwable{…}
*/
public Object around(ProceedingJoinPoint pjp){
Object obj=null;
try{
System.out.println("MoocAspect around 1.");
obj=pjp.proceed();//执行当前业务的方法
System.out.println("MoocAspect around 2.");
}catch(Throwable e){
e.printStackTrace();
}
return obj;
}
}
//业务类
public class AspectBiz {
public void biz() {
System.out.println("AspectBiz biz.");
// throw new RuntimeException();
}
}
单元测试
@Test
public void testBiz() {
AspectBiz biz = super.getBean("aspectBiz");
biz.biz();
}
执行单元测试方法,输出
MoocAspect before.
MoocAspect around 1.
AspectBiz biz.
MoocAspect around 2.
MoocAspect afterReturning.
MoocAspect after.
即使是抛出异常了,也会执行after这个方法,输出为
MoocAspect before.
MoocAspect around 1.
AspectBiz biz.
MoocAspect around 2.
MoocAspect afterThrowing.
MoocAspect after.
aop:pointcut中的expression就是一个切入点的表达式,execution执行方法在* com.imooc.aop.schema.advice.biz这个包下所有以Biz结尾的类的所有方法,这里是AspectBiz类里边有个biz方法。这个切入点切到了这个表达上,它的id是moocPointcut。
aop:before中的before方法什么时候会被触发?就是当对应包下边所有以Biz结尾的类的方法在执行之前都会执行这个方法,也就是MoocAspect的before方法。因为这个pointcut-ref引用的就是这样的一个pointcut。
Advice parameters
public class AspectBiz {
public void biz() {
System.out.println("AspectBiz biz.");
// throw new RuntimeException();
}
public void init(String bizName, int times) {
System.out.println("AspectBiz init : " + bizName + " " + times);
}
}
回到配置文件里 仍然使用around,pointcut写得具体一些,AspectBiz里的init方法,参数分别是String,int,后边要加上参数名称。
<aop:around method="aroundInit"
pointcut="execution(* com.imooc.aop.schema.advice.biz.AspectBiz.init(String, int)) and args(bizName, times)"/>
实现类的aroundInit方法,和之前around方法不同的是,要加上两个参数
public Object aroundInit(ProceedingJoinPoint pjp, String bizName, int times) {
System.out.println(bizName + " " + times);
Object obj = null;
try {
System.out.println("MoocAspect aroundInit 1.");
obj = pjp.proceed();
System.out.println("MoocAspect aroundInit 2.");
} catch (Throwable e) {
e.printStackTrace();
}
return obj;
}
单元测试
@Test
public void testInit() {
AspectBiz biz = super.getBean("aspectBiz");
biz.init("moocService", 3);
}
带参数的环绕通aroundInit知包含在不带参数的around中