zoukankan      html  css  js  c++  java
  • 面向切面编程AOP:基于注解的配置

    Aop编程就是面向编程的羝是切面,而切面是模块化横切关注点。

         -切面:横切关注点,被模块化的特殊对象。

         -通知:切面必须要完成的工作

         -目标:被通知的对象

         -代理:向目标对象应用通知之后创建的对象。

         -连接点:程序执行的某个特定的位置。

        -切点:相当于查询条件

    其配置文件如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop.xsd">
           <!--加入自动扫描的包-->
           <context:component-scan base-package="com.sevenhu.AOPTests"></context:component-scan>
           <!--使AspesctJ的注解起作用-->
           <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    </beans>
    

     声明切面的两种方式:

           1.基于XML配置文件的方式:只需要在IOC容器中将切面声明为bean实例,当在Spring IOC容器中初始化AspectJ切面之后,Spring IOC容器会为那些与AspectJ切面相匹配的bean创建代理。

           2.基于注解的方式:在AspectJ注解中,切面只是一个带有@Aspect注解的java类。

    AspectJ支持5中类型的通知注解:

    1.@Before:前置通知,在方法执行前执行

    2.@After:后置通知,在方法执行后执行

    3.@AfterReturning:返回通知,在方法返回结果之后执行

    4.@AfterThrowing:异常通知,在方法抛出异常之后执行

    5.@Around:环绕通知,围绕着方法执行。

    上代码,首先建立一个bean实例:

    package com.sevenhu.AOPTests;
    
    import org.springframework.stereotype.Component;
    
    /**
     * Created by hu on 2016/4/1.
     */
    @Component
    public class Calculator {
        //加
        public int add(int a,int b){
            return a+b;
        }
        //减
        public int sub(int a,int b){
            return a-b;
        }
        //乘
        public int multiply(int a,int b){
            return a*b;
        }
        //除
        public double divide(int a,int b) throws Exception {
            if(b==0){
                throw new Exception();
            }else{
                return a/b;
            }
        }
    }
    

      切面代码如下:

    package com.sevenhu.AOPTests;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.springframework.stereotype.Component;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    
    /**
     * Created by hu on 2016/4/1.
     */
    @Aspect
    @Component
    public class AspectDemo {
        //可以在通知方法中声明一个类型为JoinPoint的参数,然后就可以访问链接的细节,如方法名和参数值
    
        //前置通知
        @Before("execution(public int com.sevenhu.AOPTests.Calculator.*(int ,int ))")
        public void beforeMethod(JoinPoint joinPoint){
            String methodName=joinPoint.getSignature().getName();
            Object[] args=joinPoint.getArgs();
            System.out.println("The method "+methodName+" begins with "+ Arrays.asList(args));
        }
        //后置通知:在连接点完成之后执行,即连接点返回结果或抛出异常的时候。
        @After("execution(public int com.sevenhu.AOPTests.Calculator.*(int ,int ))")
        public void afterMethod(JoinPoint joinPoint){
            String methodName=joinPoint.getSignature().getName();
            System.out.println("The method "+methodName+" ends");
        }
        //返回通知:只在连接点返回结果的时候执行(即不抛出异常),并且还可以访问返回结果
        @AfterReturning(pointcut = "execution(public int com.sevenhu.AOPTests.Calculator.*(int ,int ))",returning = "result")
        public void afterMethodReturning(JoinPoint joinPoint,Object result){//必须在方法签名中添加一个同名的参数“result”,Spring会通过这个参数传递返回值
            String methodName=joinPoint.getSignature().getName();
            System.out.println("The method "+methodName+" ends with a returning value "+result);
        }
        //异常通知:只有在连接点抛出异常的时候才会执行异常通知
        @AfterThrowing(pointcut = "execution(public int com.sevenhu.AOPTests.Calculator.*(int ,int ))",throwing = "e")
        public void afterMethodThrowing(JoinPoint joinPoint,Exception e){//必须在方法签名中添加一个同名的参数“e”,Spring会通过这个参数传递异常对象
            String methodName=joinPoint.getSignature().getName();
            System.out.println("The method "+methodName+" has thrown a exception: "+e.getMessage());
        }
        //环绕通知:环绕通知是所有通知中功能最为强大的,能够全面控制连接点,甚至可以控制是否执行连接点,对于环绕通知,连接点参数是必须的
        /*
        * ProceedingJoinPoint是JoinPoint的子接口,允许控制何时执行,是否执行连接点
        * 在环绕通知中需要明确调用ProceedingJoinPoint的proceed()方法来执行被代理的方法,如果忘记这样做就会导致通知被执行了,但是目标方法没有被执行。
        * 注:环绕通知的方法需要返回目标方法执行之后的结果,即joinPoint.proceed();的返回值,否则 会出现空指针异常
        * */
        @Around("execution(public int com.sevenhu.AOPTests.Calculator.*(int ,int ))")
        public void aroundMethod(ProceedingJoinPoint joinPoint)  {
            String methodName=joinPoint.getSignature().getName();
            System.out.println("The method "+methodName+" begins");//相当于前置通知
            try{
                joinPoint.proceed();//执行连接点方法
            }catch (Throwable e){
                System.out.println("An Exception happened");//相当于异常通知
            }
            System.out.println("The method "+methodName+" ends");//相当于后置通知
        }
    }
    

      指定切面的优先级

        在同一个连接点上可能不止一个切面,除非明确指定,否则它们的优先级是不确定的,切面的优先级可以通过实现Ordered接口 或@Order注解指定。

        实现Order接口,getOrder()方法的返回值越小,优先级越高,常用的也就是使用注解的方式,所以具体方法如下:

    @Aspect
    @Order(0)
     class Order1{
         ...
     }
    @Aspect
    @Order(1)
    class Order2{
        ...
    }
    

    重用切入点定义

         在编写AspectJ切面时,可以直接在通知注解中书写切入点表达式,但是一个切入点表达式可能会在通知中重复出现。在AspectJ切面中,可以通过@PointCut注解将一个切入点声明成简单的方法,切入点的方法体通常是空的。其具体用法如下:

        @Pointcut("execution(* *.*(..)")
        private void pointCut(){}
    
        @Before("pointCut()")
        public void beforeMethod(){
            System.out.println("doning sth...");
        }
    

      

        

  • 相关阅读:
    如何让Surface RT支持网站的flash
    C# 线程同步
    WPF中Visible设为Collapse时,VisualTreeHelper.GetChildrenCount为0
    Set connectionId threw an exception.
    C# 深化基本概念
    wpf如何获取control template里的元素
    DataGrid当列宽超出当前宽度时,没有数据也恒有滚动条
    利用MEF实现插件机制(可根据输入类型来加载特定dll)
    利用正则表达式类解析SQL语句,达到Worklist兼容各个RIS数据库的目的
    Mysql 创建存储过程 更新表
  • 原文地址:https://www.cnblogs.com/hujingwei/p/5344227.html
Copyright © 2011-2022 走看看