使用AspectJ开发AOP
标签:Spring

使用AspectJ开发AOP

1. AspectJ 简介

2. 基于@AspectJ 编程

  1. 下载 导入 aspectJ 开发包 (AspectJ 依赖 AOP 的 jar包 )

    AspectJ开发包 `com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar`
    

    导入spring 整合 aspectj 的jar包 spring-aspects-3.2.0.RELEASE.jar

  2. 编写Spring配置文件 (需要aop名称空间)

使用 <aop:aspectj-autoproxy /> 配置自动代理,底层为 <bean class="... AnnotationAwareAspectJAutoProxyCreator" />

2.1 @AspectJ提供不同的通知类型

2.2 切点表达式定义

切点使用指定哪些连接点 会被增强 , 通过execution函数,可以定义切点的方法切入

语法execution(<访问修饰符><返回类型><方法名>(<参数>)<异常>)

MyAspect:

@Aspect
@Component
public class MyAspect {

    @Before("execution(* com.liuyao.aspectj.UserDAO.add(..))")
    public void before1() {
        System.out.println("===before1===");
    }
}

3. @AspectJ 支持通知类型详解(注解方式)

步骤

  1. 导入Jar包
  2. 编写被代理对象
  3. 编写切面类
  4. 配置applicationContext.xml,注册代理对象和切面类

3.1 @Before

前置通知 @Before : 前置通知 , 每个前置通知方法接收JoinPoint

第二步:编写被代理对象

package com.liuyao.aspectj;

import org.springframework.stereotype.Component;

/**
 * Created By liuyao on 2018/5/12 16:45.
 */
@Component
public class UserDAO {
    public void add() {
        System.out.println("user add");
    }
}

第三步:编写切面类

@Aspect  // 声明这是一个切面类
@Component
public class MyAspect {

   @Before("execution(* com.liuyao.aspectj.UserDAO.add(..))")
   public void before(JoinPoint joinPoint) {
       System.out.println("===before===");
       // 获得拦截的方法信息
       System.out.println(joinPoint.toString());
   }
}

第四步:注册被代理对象和切面

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
   	<!--启用AspectJ自动代理--> 
    <aop:aspectj-autoproxy/>
    <!--被代理目标-->
    <bean id="userDAO" class="com.liuyao.aspectj.UserDAO">
    <!--切面-->
    <bean id="myaspect" class="com.liuyao.aspect.MyAspect">
</beans>

结果是:

3.2 @AfterReturning

后置通知 @AfterReturning : 后置通知,

@AfterReturning(value = "execution(* com.liuyao.aspectj.UserDAO.delete(..))", returning = "returnValue")
    public void afterReturning(Object returnValue) {
        System.out.println("===afterRturning===");
        System.out.println(returnValue);
    }

3.3 @Around

环绕通知 @Around : 在目标方法前后增强 ,

    @Around("execution(* com.liuyao.aspectj.UserDAO.delete(..))")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("===before around===");
        Object res = proceedingJoinPoint.proceed();
        System.out.println("===after around===");
        return res;
    }

3.4 @AfterThrowing

抛出通知 @AfterThrowing :

 @AfterThrowing(value = "execution(* com.liuyao.aspectj.UserDAO.delete(..))", throwing = "e")
    public void afterThrowing(Throwable e) {
        System.out.println(e.getMessage());
    }

3.5 @After

最终通知 @After :

@After("execution(* com.liuyao.aspectj.UserDAO.delete(..))")
public void after() {
	System.out.println("===after===");
}

3.6 @Pointcut

在通知上定义切点表达式,会造成一些切点表达式重复,在每个通知内定义切点,会造成工作量大,不易维护,对于重复的切点,可以使用@Pointcut进行定义。

@Pointcut("execution(* com.liuyao.aspectj.UserDAO.delete(..))")
 private void myPonitcut() { }

面试题 : advisor 和 aspect 区别 ?

4. 使用XML方式配置AspectJ

MyXMLAspect:

package com.liuyao.aspectj;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

/**
 * Created By liuyao on 2018/5/12 16:46.
 */
public class MyXMLAspect {

    public void before(JoinPoint joinPoint) {
        System.out.println("===before===");
        System.out.println(joinPoint.toString());
    }

    public void afterReturning(Object returnValue) {
        System.out.println("===afterRturning===");
        System.out.println(returnValue);
    }

    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("===before around===");
        Object res = proceedingJoinPoint.proceed();
        System.out.println("===after around===");
        return res;
    }

    public void afterThrowing(Throwable e) {
        System.out.println(e.getMessage());
    }

    public void after() {
        System.out.println("===after===");
    }

}

ApplicationContext.xml

 <bean id="userDAO" class="com.liuyao.aspectj.UserDAO"></bean>
 <bean id="myXMLAspect" class="com.liuyao.aspectj.MyXMLAspect"></bean>
    <aop:config>
        <aop:aspect ref="myXMLAspect">
            <aop:pointcut id="myPointcut"expression="execution(* com.liuyao.aspectj.UserDAO.delete(..))"></aop:pointcut>
            <aop:before method="before" pointcut-ref="myPointcut"></aop:before>
            <aop:after-returning method="afterReturning" pointcut-ref="myPointcut"returning="returnValue"></aop:after-returning>
            <aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut" throwing="e"></aop:after-throwing>
            <aop:around method="around" pointcut-ref="myPointcut"></aop:around>
            <aop:after method="after" pointcut-ref="myPointcut"></aop:after>
        </aop:aspect>
    </aop:config>

测试结果:

  • 7 min read

CONTRIBUTORS


  • 7 min read