spring中使用aop介绍

背景

最近在看 spring实战,看到第四章也就是”面向切面的Spring”。
看到其中说”在一个地方定义通用功能,但是我们可以通过声明的方法定义这个功能在何处应用无需修改受影响的类,这些类称之为切面“。上面这段话,我们其实只要抓住几个关键词 :

  • 通用功能:什么样的功能叫通用功能呢,比如日志、事务之类。
  • 何处使用:在什么地方会使用上日志、事务。
  • 无需修改:这算是aop 的一个特点吧,举个例子 ,如果你要在每个方法上加入日志,最简单最傻的方法是一个个加log,那么会带来一个问题,修改起来特别麻烦。这个时候就需要用到aop了。

AOP术语

  1. 通知:切面的工作被称为通知,他应该应用于某个方法被调用之前?之后?之前和之后?还是抛出异常?
    • Spring 有5种类型的通知。
      • Before 方法调用之前
      • After 执行之后,无论方法是否成功。
      • After-returning 方法调用成功之后
      • After-throwing 方法抛出异常
      • Around 通知包裹着被通知的方法。中间可以使用point.proceed() 继续执行方法。
  2. 连接点:应用执行过程中插入切面的一个点,这个点可以是调用方法的时候、抛出异常。
  3. 切点: 定义在“何处”开始进行通知。
  4. 切面:切面是切点的集合
  5. 引入:引入允许我们向先有的类添加新的方法。
  6. 织入:织入是将切面应用到目标对象来创建的代理对象过程。(不是特别懂!).
    最常用的估计也就是切点、连接点、通知、和切面。

Spring中该如何使用AOP

spring 中使用AOP有2种方法:一种是通过xml来配置。一种是通过注解的方式。我首先介绍xml方式。首先不管是xml配置还是注解配置,在配置文件中都得有AOP的命空间,具体如下所示:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd">

1. xml配置

配置如下:

<bean id="systemLog" class="com.storm.aop.SystemLog"/>
<!--spring处理AOP代理有2种代理实现方式,一种是默认的JDK代理实现,一种是cglib代理实现,这里false 就是默认的,true是使用cglib代理 --!>
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!--所有配置都在这里 --!>
    <aop:config>
        <aop:aspect id="systemLog" ref="systemLog">
            <aop:pointcut id="log" expression="execution(* com.storm.controller.UserController.*(..))"/>
            <aop:before method="doBefore" pointcut-ref="log"/>
            <aop:after method="doAfter" pointcut-ref="log"/>
            <aop:around method="doAround" pointcut-ref="log"/>
        </aop:aspect>
    </aop:config>

下面我就对这段代码进行解释

<bean id="systemLog" class="com.storm.aop.SystemLog"/>`
<aop:aspect id="systemLog" ref="systemLog">

<aop:aspect>声明一个切面类,这里是指向的一个 SystemLog bean类。

aop:pointcut id="log" expression="execution(* com.storm.controller.UserController.*(..))"/>

这里是定义了一个切点,是指在 com.storm.controller.UserController 这个类里面 所有的方法 ((..)是表示不管无参有参的方法)都会通过aop去代理。
execution(* ) 这个 * 是通配符表示返回任意类型。
比如 我要controller这个包下的所有方法都要经过AOP:

aop:pointcut id="log" expression="execution(* com.storm.controller.*.*(..))"/>
<aop:before method="doBefore" pointcut-ref="log"/>
<aop:after method="doAfter" pointcut-ref="log"/>
<aop:around method="doAround" pointcut-ref="log"/>

都是通知 这就对应了我前面所说的几种通知方式(忘了可以回头看看)。method对应具体实现的方法。

xml配置完成之后,我们就要编写通知类(也就是上面的 SystemLog),具体代码如下所示:

public class SystemLog {

    public void doBefore()  {
        System.out.println("begin  method");
    }

    public void doAfter() {
        System.out.println("end method");
    }

    public Object doAround(ProceedingJoinPoint joinpoint) {
        Object result = null;
        System.out.println("around begin");
        try {
            result = joinpoint.proceed();

        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("around end");
        return result;

    }
}

我们可以看到 这里的doBefore 和doAfter doAround 就是 xml配置中method 所指向的方法。
到这里 xml 配置已经完成,运行项目,我们可以看到如下的结果:(库日天cj就是程序运行过程中输出的信息)
运行结果

xml配置方法总结:
xml配置只要记着两个步骤就可以:

  1. 配置文件中配置AOP相关信息。参见配置文件
  2. 通知类编写。(通知类中如何获取参数信息 可以通过JoinPoint 这个类来获取)

2 注解配置

注解这种方式相比较xml,形式上更为简洁,所以我推荐使用注解使用,不然一大推东西都在xml 中,找都找不到。
配置文件如下:(其实只要在spring-mvc 配置文件中加入一行就好了)

<aop:aspectj-autoproxy proxy-target-class="true"/>

对应的通知类

package com.storm.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * Created by cj on 2018/3/11.
 */
@Aspect
@Component
public class SystemLog {
    /**
     * Created by cj on 2018/3/11.
     */
    public  void SystemLog(){
        System.out.println("loading  systemLog");
    }

    @Pointcut("execution(* com.storm.controller.*.*(..))")
    public void action() {
    }

    @Before("action()")
    public void doBefore(JoinPoint joinPoint) {
        System.out.println("----------------------");
        System.out.println("begin  method");
    }

    @After("action()")
    public void doAfter(JoinPoint joinPoint) {
        System.out.println("end method");
    }

    @Around("action()")
    public Object doAround(ProceedingJoinPoint joinpoint) {
        Object result = null;
        System.out.println("around begin");
        try {
            result = joinpoint.proceed();

        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("around end");
        return result;

    }
}

执行结果如下:
运行结果

总结:

对于spring中aop 的使用 需要注意的几点:

  1. 在编写切点时 先尽量将范围缩小到具体的某一个方法,从具体的某一个方法开始。这样才能避免出错。
  2. 在编写通知类是,我建议多写一个构造函数,早构造函数里打印一些信息,这些信息会帮助你排除一些错误。
  3. 如果要对controller层进行AOP管理,有关AOP配置的信息写到spirng-mvc配置文件中(我也不知道为什么)。
  4. 其实记住以上几个步骤。只需要记住2个问题:1 我对什么类或者方法感兴趣(也就是PointCut)。2 我该在这个方法的什么时期进行我自定义的操作(也就是Advice).

结束语:

新人的真正意义上的第一篇博客,希望看过的人都能评论下,也希望顺手给个关注,以后每周都会更新,虽不是什么很牛逼的博文,但我保证都是用心写,谢谢大家!!!!!!!!!!

猜你喜欢

转载自blog.csdn.net/bicheng4769/article/details/79501263