Spring AOP笔记
博客专区 > whc20011 的博客 > 博客详情
Spring AOP笔记
whc20011 发表于1年前
Spring AOP笔记
  • 发表于 1年前
  • 阅读 11
  • 收藏 1
  • 点赞 0
  • 评论 0

【腾讯云】新注册用户域名抢购1元起>>>   

 一、概念定义

     通知:定义了切面的"什么"和"何时"。

     切点:定义了切面的"何处"。用于准确定位应该在什么地方应用切面的通知。

     切面:切面是通知和切点的集合。

     连接点:在应用执行过程中能够插入切面的一个点。

     织入:将切面应用到目标对象来创建新的代理对象的过程。

二、使用切点选择连接点

    在Spring AOP中,需要使用AspectJ的切点表达式语言来定义切点。Spring仅支持AspectJ切点指示器的子集。其中只有execution指
示器是唯一的执行匹配,其他的指示器都是限制匹配的。

    1、切点的编写

        示例1:execution(* com.springinaction.springidol.Instrument.play(...))
                我们使用execution()指示器选择Instrument的play()方法。方法表达式以*号隔开,标识了我们不关心方法返回值的类型。然后,我们制订了全限定名和方法。方法中的(...)标识切点选择任意的play()方法,无论方法入参是什么。

    示例2:execution(* com.springinaction.springidol.Instrument.play(...)) && within(com.springinaction.spriingidol.*)
                我们使用within()指示器来限制切点仅匹配com.springinaction.springidol包。

三、在XML中声明切面

   1、 声明前置通知和后置通知:
    声明一个audience Bean:
    <bean id="audience" class="com.springinaction.springidol.Audience" />

    把audience Bean声明为一个切面:
    <aop : config>
        <aop : aspect ref="audience">
            <aop : before pointcut="execution(* com.springinaction.springidol.Performer(...))" method="takeSeats" />
            <aop : before pointcut="execution(* com.springinaction.springidol.Performer(...))" method="turnOffCellPhones" />
            <aop : after-returning  pointcut="execution(* com.springinaction.springidol.Performer(...))" method="applaud" />
            <aop : after-throwing pointcut="execution(* com.springinaction.springidol.Performer(...))" method="demandRefund" />
        </aop : aspect>
    </aop : config>

pointcut属性的值定义了通知应用的切点。pointcut属性的值是使用AspectJ切点表达式语法所定义的切点。

定义一个命名切点消除冗余的切点定义:
    
    <aop : config>
        <aop : aspect ref="audience">
            <aop : pointcut id="performance" expression="execution(* com.springinaction.springidol.Performer(...))">
            <aop : before pointcut-ref="performance" method="takeSeats" />
            <aop : before pointcut-ref="performance" method="turnOffCellPhones" />
            <aop : after-returning  pointcut-ref="performance" method="applaud" />
            <aop : after-throwing pointcut-ref="performance" method="demandRefund" />
        </aop : aspect>
    </aop : config>

 
  2、声明环绕通知
        这是环绕通知方法:
        public void watchPerformance(ProceedingJoinPoint  joinpoint){
            try{
                System.out.println("The audience is taking their seats.");                //表演之前
                System.out.println("The audience is turning off their cellphones.");

                joinpoint.proceed();                        //执行被通知的方法

                long end = System.currentTimeMillis();                        //表演之后
                System.out.println("CLAP CLAP CLAP CLAP CLAP CLAP ");
                System.out.println("The performance took " + (end - start));
            }catch(Throwable t){
                 System.out.println("Boo! we want our money back!");               //表演失败之后
             }
        }

        该通知方法使用了ProceedingJoinPoint作为方法的入参,该对象能让我们在通知里调用被通知的方法。
        如果我们忘记调用proceed()方法,通知将会阻止被通知方法的调用。
        在此audience切面,watchPerformance()方法包含之前4个通知方法的所有逻辑,但所有逻辑都放在一个方法中了。

    声明环绕通知:
    <aop : config>
        <aop : aspect ref="audience">
            <aop : pointcut id="performance2" expression="execution(* com.springinaction.springidol.Performer(...))">
            <aop : around pointcut-ref="performance" method="watchPerformance()" />
        </aop : aspect>
    </aop : config>

3、为通知传递参数
 
有时候通知并不仅仅是对方法进行简单的包装,还需要检验传递给方法的参数值,这时候为通知传递参数就非常有用了。

四、注解切面

    1、注解前置、后置通知:

    package  com.springinaction.springidol;

    @Aspect                                                             
    public class Audience {
        @Pointcut(                                                   //定义切点
                        "execution(* com.springincation.springidol.Performer.perform( .. ))")
    public void performance(){
    }
    
    @Before("performance()")                            //表演之前
    public void takeseats(){
        System.out.println("The audience is taking their seats.");
   
    @Before("performance()")                           //表演之前
    public void turnoffCellPhones(){
        System.out.println("The audience is turning off their cellphones.");
    
    
    @AfterReturning("performance()")            //表演之后
    public void applaud(){
        System.out.println("CLAP CLAP CLAP CLAP CLAP");

    @AfterThrowing("performance()")            //表演失败之后
    public void demandRefund(){
        System.out.println("Boo! We want our money back!");
    }
    }

    新的Audience类使用@AspectJ注解进行了标注。该注解标注了Audience不仅仅是一个POJO,还是一个切面。

    @pointCut注解用于定义一个可以在@AspectJ切面内可重用的切点。切点的名称来源于注解所应用的方法名称。因此该切点名称为performance()。performance()方法在这里是空的,该方法本身只是一个标识,供@pointCut注解依附。

2、注解环绕通知:

    @Around("performance()")
    public void watchPerformance(ProceedingJoinPoint joinpoint){
        try{
            System.out.println("The audience is taking their seats.");
            System.out.println("The audience is turning off their cellphones.");
            
            long start = System.currentTimeMillis();
            joinpoint.proceed();
            long end = System.currentTimeMillis();

            System.out.println("CLAP CLAP CLAP CLAP CLAP !");
            System.out.println("The performance took" + (end - start) + "milliseconds");
        }catch(Throwable t ){
            System.out.println("Boo! We want our money back!");
        }
    }
 

标签: Spring AOP
  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
粉丝 0
博文 48
码字总数 29579
×
whc20011
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: