首页 > 其他 > 详细

AOP切面

时间:2020-03-22 20:30:24      阅读:62      评论:0      收藏:0      [点我收藏+]

一、存在的问题:为方法添加日志和验证功能

  • 代码混乱:越来越多的非业务需求(日志和验证等)加入后,原有的业务方法急剧膨胀。每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点
  • 代码分散:以日志需求为例,只是为了满足这个单一需求,就不得不在多个模块(方法)里多次重复相同的日志代码。如果日志需求发生变化,必须修改所有模块
  • AOP编程便是为了解决上述问题

二、解决方案

  1. 使用动态代理
  • 代理设计模式的原理:使用一个代理将对象包装起来,然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理,代理对象决定是否以及何时将方法调用转到原始对象上。
  1. AOP
  • AOP(Aspect-Oriented Programming,面向切面编程):是一种新的方法论,是对传统OOP(Object-Oriented Programming)的补充
  • AOP的主要编程对象是切面(aspect),而切面模块化横切关注点
  • 在应用AOP编程时,仍然需要定义公共功能,但可以明确的定义这个功能再哪里,以什么方式应用,并且不必修改受影响的类。这样一来横切关注点就不模块化到特殊的对象(切面)里。
  • AOP的好处
    • 每一个事物逻辑位于一个位置,代码不分散,便于维护和升级
    • 业务模块更简洁,只包含核心业务代码

技术分享图片

三、AOP术语

  • 切面(Aspect):横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象
  • 通知(Advice):切面必须要完成的工作
  • 目标(Target):被通知的对象
  • 代理(Proxy):向目标对象应用通知之后创建的对象
  • 连接点(Joinpoint):程序执行的某个特定位置;如类某个方法调用前、调用后、方法抛出异常后等。连接点由两个信息确定:方法表示的程序执行点;相对点表示的方位。
  • 切点(pointcut):每个类都拥有多个连接点,连接点是程序类中客观存在的事务。AOP通过切点定位到特定的连接点。类比:连接点相当于数据库中的记录,切点相当于查询条件。切点和连接点不是一对一的关系,一个切点匹配多个连接点,切点通过org.springframework.aop.Pointcut接口进行描述,它使用类和方法作为连接点的查询条件。

AspectJ:java社区里最完整最流行的AOP框架
在Spring2.0以上版本,可以使用基于AspectJ注解或基于XML配置的AOP

四、使用

  1. 加入jar包:AspectJ
  2. 在配置文件中加入aop的命名空间
  3. 在配置文件中加入配置(通过注解)
<!--使AspectJ注解起作用,自动为匹配的类生成代理对象-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
  1. 前置通知
  • 把横切关注点的代码抽象到切面的类中

    1. 切面首先是一个IOC中bean,即加入@Component注解
    2. 切面还需要加入@Aspect注解
    3. 在切面类中声明各种通知。在方法前加入@Before注释。方法内可以使用JoinPoint参数,访问细节。
@Before("execution(public int com.atguigu.spring.aopimpl.ArithmeticCalculator.*(..))")
public void beforeMethod(JoinPoint joinPoint){
    String methodName = joinPoint.getSignature().getName();
    List<Object> args = Arrays.asList(joinPoint.getArgs());


    System.out.println("The method:"+methodName+" begin with:"+args);
}
  1. 后置通知:目标方法执行后(无论是否异常),执行的通知
    与@Before一样,在通知方法前使用注释@After
    后置通知中还不能访问目标方法执行的结果
@After("execution(public int com.atguigu.spring.aopimpl.ArithmeticCalculator.*(..))")
public void afterMethod(JoinPoint joinPoint){
    String method = joinPoint.getSignature().getName();
    List<Object> args = Arrays.asList(joinPoint.getArgs());
    System.out.println("The method:"+method+" end with"+args);
}
  1. 返回通知:目标正常执行后执行的通知
    可以访问到方法的返回值
@AfterReturning(value = "execution(public int com.atguigu.spring.aopimpl.ArithmeticCalculator.*(..))",
        returning = "result")
public void aftetReturning(JoinPoint joinPoint,Object result){
    String methodName = joinPoint.getSignature().getName();
    List<Object> args = Arrays.asList(joinPoint.getArgs());
    System.out.println("The method:"+methodName+" end with"+result);
}
  1. 异常通知
    目标方法出现异常会执行的diamante,可以访问到异常对象;其可以在出现指定异常时执行。
  2. 环绕通知
    环绕通知需要携带ProceedingJoinPoint类型的参数。环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法。且环绕通知必须有返回值,返回值即目标方法的返回值。
@Around("execution(public int com.atguigu.spring.aopimpl.ArithmeticCalculator.*(..))")
public Object around(ProceedingJoinPoint pjp){
    Object result = null;
    String methodName = pjp.getSignature().getName();
    List<Object> args = Arrays.asList(pjp.getArgs());
    try {
        //前置通知
        System.out.println("The method:"+methodName+" begin with:"+args);
        result = pjp.proceed();
        //返回通知
        System.out.println("The method:"+methodName+" end with:"+result);
    } catch (Throwable throwable) {
        //异常通知
        System.out.println("The method:"+methodName+" occurs with:"+throwable);
    }
    //后置通知
    System.out.println("The method "+methodName+" ends");
    return result;
}

五、切面的优先级

@Order(level)指定切面的优先级,值越小优先级越高

六、切点表达式

  • 定义一个方法,用于声明切点表达式。一般地,该方法不需要再添入其他代码。
  • 使用@Piintcut来声明切入点表达式
  • 后面的其他通知直接使用方法名来引用切点表达式
    //切点表达式
    @Pointcut("execution(public int com.atguigu.spring.aopimpl.ArithmeticCalculator.*(..))")
    public void declareJoinPoint(){}

    //引用方式
    @Before("declareJoinPoint()")
    public void beforeMethod(JoinPoint joinPoint){

七、基于配置文件的方式来配置AOP

<aop:config>
    <!--配置切点表达式-->
    <aop:pointcut id="pointcut" expression="execution(* com.atguigu.spring.aopxml.ArithmeticCalculator.*(..))"/>
    <!--配置切面-->
    <aop:aspect ref="loggingAspect" order="2">
        <!--配置通知-->
        <aop:before method="beforeMethod" pointcut-ref="pointcut"></aop:before>
        <aop:after method="afterMethod" pointcut-ref="pointcut"></aop:after>
        <aop:after-returning method="aftetReturning" pointcut-ref="pointcut" returning="result"></aop:after-returning>
        <aop:after-throwing method="aftetThrowing" pointcut-ref="pointcut" throwing="ex"></aop:after-throwing>
    </aop:aspect>
</aop:config>

AOP切面

原文:https://www.cnblogs.com/ylcc-zyq/p/12547919.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!