Spring入门(Schema-based AOP其三)

Advice应用

配置完了切入点,接下来要配置advice,也就是通知的配置。

Before advice

Before advice是前置通知

前置通知的方式是aop:before,然后有一个pointcut-ref是引用某一个切入点,还有一个method,就是前置通知会调用哪一个方法去执行。这个方法是ref对应bean中的方法。

<aop:aspect id="beforeExample" ref="aBean">
    <aop:before pointcut-ref="dataAccessOperation" method="doAccessCheck"/>
    ...
</aop:aspect>

也可以在aop:before里边直接指定pointcut,method不变。

<aop:aspect id="beforeExample" ref="aBean">
    <aop:before pointcut="execution(*com.xyz.muapp.dap..(..))" 
        method="doAccessCheck"/>
    ...
</aop:aspect>

在之前的例子里看一下怎么声明:

<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"/>

    </aop:aspect>
</aop:config>

before的method声明成before,pointcut-ref来引用刚刚才声明好的moocPiontcut,这就是前置通知。

然后在类moocAspect里边定义一个before方法。

public class MoocAspect{

    public void before(){
        System.out.println("MoocAspect Before.");
    }
}

之后在AspectBiz业务类里边定义一个方法

public class AspectBiz {

    public void biz() {
        System.out.println("AspectBiz biz.");
    }
}

然后看一下单元测试类的写法

@Test
public void testBiz() {
    AspectBiz biz = super.getBean("aspectBiz");
    biz.biz();
}

执行单元测试方法,看到输出
MoocAspect Before.
AspectBiz biz.

MoocAspect被我们声明成了切面类,里边有一个method叫before。
aop:pointcut中的expression就是一个切入点的表达式,execution执行方法在* com.imooc.aop.schema.advice.biz这个包下所有以Biz结尾的类的所有方法,这里是AspectBiz类里边有个biz方法。这个切入点切到了这个表达上,它的id是moocPointcut。
aop:before中的before方法什么时候会被触发?就是当对应包下边所有以Biz结尾的类的方法在执行之前都会执行这个方法,也就是MoocAspect的before方法。因为这个pointcut-ref引用的就是这样的一个pointcut。

After returning advice

返回之后的通知

它是用的aop:after-returning,里边的pointcut-ref也是引用某一个切入点,method是在这个切入点上要执行的方法是什么样的。

<aop:aspect id="afterReturningExample" ref="aBean">
    <aop:after-returning pointcut-ref="dataAccessOperation" method="doAccessCheck"/>
    ...
</aop:aspect>

下边是另外一种配置方式,除了pointcut-ref和method之外,限制了返回值。

<aop:aspect id="afterReturningExample" ref="aBean">
    <aop:after-returning pointcut-ref="dataAccessOperation" 
        returning="retVal"
        method="doAccessCheck"/>
    ...
</aop:aspect>

继续在那里例子里写代码来试一试。

<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"/>
        <aop:after-returning method="afterReturning" pointcut-ref="moocPiontcut"/>
    </aop:aspect>
</aop:config>

同样要找到切面类,在里边写一个afterReturning方法

public class MoocAspect{

    public void before(){
        System.out.println("MoocAspect Before.");
    }

    public void afterReturning(){
        System.out.println("MoocAspect afterReturning.");
    }
}

这样在执行单元测试类时候的输出为
MoocAspect Before.
AspectBiz biz.
MoocAspect afterReturning.

After throwing advice

和after returning类似,不过是在抛出异常之后返回。

<aop:aspect id="afterThrowingExample" ref="aBean">
    <aop:after-throwing pointcut-ref="dataAccessOperation" method="doAccessCheck"/>
    ...
</aop:aspect>

这里可以使用throwing属性俩指定可被传递的异常的参数名称,和returning是一个效果。

如果在刚才的例子里继续使用,只需要在xml文件中加上这句

<aop:after-throwing method="afterThrowing" pointcut-ref="moocPointcut"/>

同时在切面类中声明一个方法

public void afterReturning(){
    System.out.println("MoocAspect afterThrowing.");
}

这时候直接执行单元测试类并没有效果,因为这个方法在异常抛出后被调用,所以可以在AspectBiz类中的biz方法里抛出一个异常。

public class AspectBiz {

    public void biz() {
        System.out.println("AspectBiz biz.");
        throw new RuntimeException();
    }
}

这时候执行的话就会发现最后的afterReturning没有了,取而代之的是afterThrowing,因为抛出了异常,无法正常返回。

After(finally) advice

返回的通知

<aop:aspect id="afterFinallyExample" ref="aBean">
    <aop:after pointcut-ref="dataAccessOperation" method="doReleaseLock"/>
    ...
</aop:aspect>

在前边的例子了进行补充

<aop:after method="after" pointcut-ref="moocPointcut"/>

在MoocAspect里要增加一个after方法

public void after(){
    System.out.println("MoocAspect after.");
}

输出的顺序为
MoocAspect before.
AspectBiz biz.
MoocAspect afterReturning.
MoocAspect after.
也就是说是最后执行的。

即使是抛出异常了,也会执行after这个方法,输出为
MoocAspect before.
AspectBiz biz.
MoocAspect afterThrowing.
MoocAspect after.

Around advice

循环通知,环绕通知
这个通知的方法的第一个参数必须是ProceedingJoinPoint类型

<aop:aspect id="aroundExample" ref="aBean">
    <aop:around pointcut-ref="businessService" method="doBasicProfiling"/>
    ...
</aop:aspect>
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable{
    Object retVal=pjp.proceed();
    return retVal;
}

这个方法doBasicProfiling必须有一个参数,第一个参数必须是ProceedingJoinPoint 这种类型,这个类型的参数有一个proceed方法,也就是执行当前业务的方法。在具体业务执行之前或者之后都可以进行我们想做的事情。

继续刚才的例子

<aop:around method="around" pointcut-ref="moocPiontcut"/>

切面类中添加方法,注意是有返回值的。

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 Object around(ProceedingJoinPoint pjp) throw Throwable{…}

运行单元测试类,结果为
MoocAspect before.
MoocAspect around 1.
AspectBiz biz.
MoocAspect around 2.
MoocAspect afterReturning.
MoocAspect after.

Advice parameters

直接看例子
在业务方法里声明另一个方法init,里边有参数。

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);
}

执行这个单元测试方法,输出
这里写图片描述
为了清晰,可以把xml文件里的其他东西注释掉。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值