Spring AOP有多种实现方式,基于Spring xml配置的,基于注解配置的,基于切点函数配置等等,还有其他的实现方式,这里主要记录提到的三种方式

一.基于xml配置的AOP

  1. 首先定义一个AOP的通知类,包含方法执行前的方法,方法执行后的方法,还有环绕等方法;如下:
/**
 * @author eleven
 * @date 2018/11/4
 * @description
 */
@Slf4j
public class GlobalAdvices {

    public void before(){
        log.warn(">>>>>前置通知:before");
    }

    public void after(){
        log.info(">>>>>后置通知:after");
    }
}
 
     2.将通知类交给spring容器管理,并且配置AOP,如下:
<bean id="globalAdvices" class="cn.eleven.common.intercept.GlobalAdvices"/>
 
<!--<!–全局的service层的方法调用都会被记录日志–>-->
<aop:config>
<aop:aspect id="class" ref="globalAdvices">//定义AOP切面
<aop:pointcut id="log" expression="execution(* cn.llf.framework.services..*.*(..))"/>//定义AOP切入点
<aop:before method="before" pointcut-ref="log"/>//前置通知方法
<aop:after method="after" pointcut-ref="log"/>//后置通知方法
</aop:aspect>
</aop:config>

      3.这样基于xml配置的AOP就算完成,所有调用service方法都会被切到;

二.基于注解配置的AOP

1.定义一个通知类,如下:
/**
* @author eleven
* @date 2018/11/4
* @description AOP
*/
@Slf4j
@Aspect
public class RequestAdvice {
/**
* 定义一个通用的切点,解决切点复用问题
*/
@Pointcut("execution(* cn.llf.framework.services..*.*(..))")
public void pointcut(){}
 
/**
* 直接在通知方法定义切点
* @param joinPoint
*/
@Before("pointcut()")
public void before(JoinPoint joinPoint){
 
log.warn(">>>>>前置通知");
}
 
/**
* 引用定义好的切点
* @param joinPoint
*/
@After("pointcut()")
public void after(JoinPoint joinPoint){
log.warn(">>>>>后置通知");
}
}
2.如 注释所说,可以定义先定义一个切入点,接着之后的各种通知就可以复用一个切入点,避免切入点代码重复;
3.对应的前制通知使用@before声明为前制通知,用@after声明为后置通知;
4.类头需要使用@asperct申明该类为切面,这样spring容器才能识别;
5.接着将该切面类收进spring容器管理,需要在xml配置,如下:
<!--基于注解的aop切面-->
<bean class="cn.llf.framework.aop.RequestAdvice"/>
6.最后还需要在spring中配置启动@asperct注解的支持,aspect注解就是包括上面的@asperct,@before等注解,配置如下:
<!-- 启动对@AspectJ注解的支持 -->
<!--<!–通知spring使用cglib而不是jdk的来生成代理方法 AOP可以拦截到Controller –>-->
<aop:aspectj-autoproxy proxy-target-class="true" />

7.上述就是基于注解的AOP的实现方式,配置完成,所有的service层的方法都已经纳入到AOP的切面范围了;

8.JoinPoint解释:进入切面之后,可以获取到拦截到的方法的一些参数信息;注意区别Joinpoint类;仅差一个P大小写问题,却关系到AOP能否启动

三.基于切点函数配置的AOP

  1. 基于切点函数的AOP,其切点函数包括9种的函数,

@AspectJ使用AspectJ专门的切点表达式描述切面,Spring所支持的AspectJ表达式可分为四类:

  • 方法切点函数:通过描述目标类方法信息定义连接点。
  • 方法参数切点函数:通过描述目标类方法入参信息定义连接点。
  • 目标类切点函数:通过描述目标类类型信息定义连接点。
  • 代理类切点函数:通过描述代理类信息定义连接点。

常见的AspectJ表达式函数:

  • execution():满足匹配模式字符串的所有目标类方法的连接点
  • @annotation():任何标注了指定注解的目标方法链接点
  • args():目标类方法运行时参数的类型指定连接点
  • @args():目标类方法参数中是否有指定特定注解的连接点
  • within():匹配指定的包的所有连接点
  • target():匹配指定目标类的所有方法
  • @within():匹配目标对象拥有指定注解的类的所有方法
  • @target():匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解
  • this():匹配当前AOP代理对象类型的所有执行方法

 

     2.上述9种切点函数种,execution函数在前面的两种实现方式已经提及,这里另外主要记录@annotation方式的切点函数 

     3.首先需要定义在方法上要使用的注解,如下:

/**
* @author eleven
* @date 2018/11/4
* @description AOP
*/
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodInvocationStatistic {
/**
* 方法作用
* @return
*/
String methodName() default "";
/**
* 方法类型
*/
int type() default 1;
}
    4.其次在需要AOP的方法上使用该注解:
@Override
@MethodInvocationStatistic(methodName = "获取用户分页数据")
public List<UserInfoPO> list(UserInfoPO query) {
List<UserInfoPO> list = dao.list(query);
return list;
}
   5.定义AOP通知类,其中的通知方法不在使用execution函数,而是使用这里提到的annotation函数,如下:
/**
* @author eleven
* @date 2018/11/4
* @description AOP
*/
@Slf4j
@Aspect
public class RequestAdvice {
/**
* 切面范围为有使用 {@link MethodInvocationStatistic}的方法
* @param joinPoint
*/
@Before("@annotation(cn.llf.framework.annotation.MethodInvocationStatistic)")
public void actionRecord(JoinPoint joinPoint){
Signature signature = joinPoint.getSignature();
log.info("标有注解的【{}】的方法被AOP切面切到,方法签名:【{}】", MethodInvocationStatistic.class.getName(),signature);
}
}
    6.同样将该通知类交给spring容器管理,如下:
<!--基于注解的aop切面-->
<bean class="cn.llf.framework.aop.RequestAdvice"/>
     7.最后还是启动aspect注解的支持
<!-- 启动对@AspectJ注解的支持 -->
<!--<!–通知spring使用cglib而不是jdk的来生成代理方法 AOP可以拦截到Controller –>-->
<aop:aspectj-autoproxy proxy-target-class="true" />