03.Spring_AOP

1.需要导入的jar包
    spring-beans-4.0.0.RELEASE.jar
    spring-context-4.0.0.RELEASE.jar
    spring-core-4.0.0.RELEASE.jar
    spring-expression-4.0.0.RELEASE.jar
    commons-logging-1.1.3.jar
    spring-aop-4.0.0.RELEASE.jar
    
      //以下是AOP需要额外导入的jar包
    com.springsource.net.sf.cglib-2.2.0.jar
    com.springsource.org.aopalliance-1.0.0.jar
    com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
    spring-aspects-4.0.0.RELEASE.jar
2.AOP中的注解
03.Spring_AOP
  • @Aspect
    • 声明某一个类是一个切面类
    • 声明为切面类的同时还需要交给IOC容器管理
@Aspect // 声明当前类是一个切面类
@Component // 将当前类交给IOC容器管理
public class LoggingAspect {
  • @Pointcut
    • 声明切入点表达式
//声明切入点表达式
@Pointcut("execution(* com.atguigu.spring.aop.ArithmeticCalculator.*(..))")
public void pointCut(){};
  • @Before
    • 声明前置通知
    • 前置通知在方法执行之前调用
// 前置通知,在目标方法调用之前执行
    @Before(value = "pointCut()")
    public void beforeAdvice(JoinPoint jp) {
         // 获取方法名
         String name = jp.getSignature().getName();
         // 获取参数
         Object[] args = jp.getArgs();
         System.out.println("[★★★Logging]The method " + name + " begins with " + Arrays.asList(args));
    }
  • @After
    • 声明后置通知
    • 后置通知在方法执行完成后调用(不管是否发生异常)
// 后置通知,在目标方法执行完成之后执行(不管是否发生异常)
    @After("pointCut()")
    public void afterAdvice(JoinPoint jp) {
         // 获取方法名
         String name = jp.getSignature().getName();
         System.out.println("[★★★Logging]The method " + name + " ends");
    }
  • @AfterReturning
    • 声明返回通知
    • 返回通知在方法执行完之后调用
//返回通知,在目标方法执行后执行
    @AfterReturning(pointcut = "execution(* com.atguigu.spring.aop.ArithmeticCalculator.*(..))",returning="result")
    public void returnAdvice(JoinPoint jp , Object result) {
         // 获取方法名
         String name = jp.getSignature().getName();
         System.out.println("[★★★Logging]The method " + name + " returns "+result);
    }
  • @AfterThrowing
    • 声明异常通知
    • 异常通知在方法执行出现异常时调用
//异常通知,在目标方法执行出现异常时执行
    @AfterThrowing(pointcut = "execution(* com.atguigu.spring.aop.ArithmeticCalculator.*(..))",throwing="e")
    public void returnAdvice(JoinPoint jp , Exception e) {
         // 获取方法名
         String name = jp.getSignature().getName();
         System.out.println("[★★★Logging]The method " + name + " occours "+e);
    }
  • @Around(使用环绕通知必须将前面的前后等方法注掉)
    • 声明环绕通知
    • 环绕通知相当于动态代理的全过程
//环绕通知,相当于动态代理的全过程
    @Around("pointCut()")
    public Object roundAdvice(ProceedingJoinPoint pjp) {
         //获取方法名
         String name = pjp.getSignature().getName();
         //获取参数
         Object[] args = pjp.getArgs();
         Object result = null;
         try {
             //前置通知
             System.out.println("[★★★★★Logging]The method " + name + " begins with " + Arrays.asList(args));
             //执行目标方法
             result = pjp.proceed();
             //返回通知
             System.out.println("[★★★★★Logging]The method " + name + " returns "+result);
         } catch (Throwable e) {
             //异常通知
             System.out.println("[★★★★★Logging]The method " + name + " occours "+e);
//           e.printStackTrace();
         } finally{
             //后置通知
             System.out.println("[★★★★★Logging]The method " + name + " ends");
         }
         return result;
    }
  • @Order
    • 声明切面的优先级
    • 通过该注解中的value属性值来设置切面的优先级,里面传入一个int类型的值,值越小优先级越高,默认值是Integer的最大值
@Order(10) //可以通过@Order注解中的value属性设置切面的优先级,value属性值越小优先级越高,默认值是Integer的最大值
@Aspect // 声明当前类是一个切面类
@Component // 将当前类交给IOC容器管理
public class ValidateAspect {
  • Spring的配置文件中的配置
<?xml version="1.0" encoding="UTF-8"?>
    
    <!-- 设置自动扫描的包 -->
    <context:component-scan base-package="com.atguigu.spring.aop"></context:component-scan>
    
    <!-- 启用 AspectJ 注解支持:Spring会自动创建代理对象 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
package com.atguigu.spring.aop;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect // 声明当前类是一个切面类
@Component // 将当前类交给IOC容器管理
public class LoggingAspect {
    
    //声明切入点表达式
    @Pointcut("execution(* com.atguigu.spring.aop.ArithmeticCalculator.*(..))")
    public void pointCut(){};
    /**
     * 切入点表达式的表示方式: ①execution(public int
     * com.atguigu.spring.aop.ArithmeticCalculator.add(int, int))
     * execution(public int ArithmeticCalculator.add(int, int))
     * -只有调用ArithmeticCalculator接口中的add()方法时才会执行对应的通知 -如果切面类与接口和实现类在同一个包下,包名可以省略
     * ②execution(public int com.atguigu.spring.aop.ArithmeticCalculator.*(int,
     * int)) --只有调用ArithmeticCalculator接口中的所有的方法时都会会执行对应的通知 ③execution(*
     * com.atguigu.spring.aop.ArithmeticCalculator.*(int, int))
     * --调用ArithmeticCalculator接口中的所有的方法时都会会执行对应的通知,而且不考虑权限修饰符和返回值类型
     * ④execution(* com.atguigu.spring.aop.ArithmeticCalculator.*(..))
     * --调用ArithmeticCalculator接口中的所有的方法时都会会执行对应的通知,而且不考虑权限修饰符和返回值类型以及参数的类型和个数
     * ⑤execution(* *.*(..)) --调用所有接口的方法时都会会执行对应的通知,而且不考虑权限修饰符和返回值类型以及参数的类型和个数
     *
     */
    // 前置通知,在目标方法调用之前执行
    @Before(value = "pointCut()")
    public void beforeAdvice(JoinPoint jp) {
        // 获取方法名
        String name = jp.getSignature().getName();
        // 获取参数
        Object[] args = jp.getArgs();
        System.out.println("[★★★Logging]The method " + name + " begins with " + Arrays.asList(args));
    }
    // 后置通知,在目标方法执行完成之后执行(不管是否发生异常)
    @After("pointCut()")
    public void afterAdvice(JoinPoint jp) {
        // 获取方法名
        String name = jp.getSignature().getName();
        System.out.println("[★★★Logging]The method " + name + " ends");
    }
    //返回通知,在目标方法执行后执行
    @AfterReturning(pointcut = "execution(* com.atguigu.spring.aop.ArithmeticCalculator.*(..))",returning="result")
    public void returnAdvice(JoinPoint jp , Object result) {
        // 获取方法名
        String name = jp.getSignature().getName();
        System.out.println("[★★★Logging]The method " + name + " returns "+result);
    }
    
    //异常通知,在目标方法执行出现异常时执行
    @AfterThrowing(pointcut = "execution(* com.atguigu.spring.aop.ArithmeticCalculator.*(..))",throwing="e")
    public void returnAdvice(JoinPoint jp , Exception e) {
        // 获取方法名
        String name = jp.getSignature().getName();
        System.out.println("[★★★Logging]The method " + name + " occours "+e);
    }
    
    //环绕通知,相当于动态代理的全过程
    @Around("pointCut()")
    public Object roundAdvice(ProceedingJoinPoint pjp) {
        //获取方法名
        String name = pjp.getSignature().getName();
        //获取参数
        Object[] args = pjp.getArgs();
        Object result = null;
        try {
            //前置通知
            System.out.println("[★★★★★Logging]The method " + name + " begins with " + Arrays.asList(args));
            //执行目标方法
            result = pjp.proceed();
            //返回通知
            System.out.println("[★★★★★Logging]The method " + name + " returns "+result);
        } catch (Throwable e) {
            //异常通知
            System.out.println("[★★★★★Logging]The method " + name + " occours "+e);
//            e.printStackTrace();
        } finally{
            //后置通知
            System.out.println("[★★★★★Logging]The method " + name + " ends");
        }
        return result;
    }
    
    
}

test
package com.atguigu.spring.test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.atguigu.spring.aop.ArithmeticCalculator;
public class AopTest {
    // 创建IOC容器
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans-aop.xml");
    @Test
    public void testAOP() {
        ArithmeticCalculator atc = (ArithmeticCalculator) ioc.getBean("arithmeticCalculator");
        // 进行加、减、乘、除的运算
        int add = atc.add(10, 2);
        System.out.println(add);
        int sub = atc.sub(10, 2);
        System.out.println(sub);
        int mul = atc.mul(10, 2);
        System.out.println(mul);
        int div = atc.div(10, 0);
        System.out.println(div);
    }
}

3.基于XML的形式配置AOP
<?xml version="1.0" encoding="UTF-8"?>
    <!-- 配置数学计算器的实现类bean -->
    <bean id="arithmeticCalculator" class="com.atguigu.spring.xml.ArithmeticCalculatorImpl"></bean>
    
    <!-- 配置切面类bean -->
    <bean id="loggingAspect" class="com.atguigu.spring.xml.LoggingAspect"></bean>
    
    <!-- 配置AOP -->
    <aop:config>
         <!-- 配置切入点表达式 -->
         <aop:pointcut expression="execution(* com.atguigu.spring.xml.ArithmeticCalculator.*(..))"
             id="pointCut"/>
         <!-- 配置切面 -->
         <aop:aspect ref="loggingAspect">
             <!-- 前置通知 -->
             <aop:before method="beforeAdvice" pointcut-ref="pointCut"/>
             <!-- 后置通知 -->
             <aop:after method="afterAdvice" pointcut-ref="pointCut"/>
             <!-- 返回通知 -->
             <aop:after-returning method="returnAdvice" pointcut-ref="pointCut" returning="result"/>
             <!-- 异常通知 -->
             <aop:after-throwing method="exceptionAdvice" pointcut-ref="pointCut" throwing="e"/>
             <!-- 环绕通知 -->
             <aop:around method="roundAdvice" pointcut-ref="pointCut"/>
         </aop:aspect>
    </aop:config>
</beans>
package com.atguigu.spring.xml;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
public class LoggingAspect {
    
    // 前置通知,在目标方法调用之前执行
    public void beforeAdvice(JoinPoint jp) {
        // 获取方法名
        String name = jp.getSignature().getName();
        // 获取参数
        Object[] args = jp.getArgs();
        System.out.println("[▲Logging]The method " + name + " begins with " + Arrays.asList(args));
    }
    // 后置通知,在目标方法执行完成之后执行(不管是否发生异常)
    public void afterAdvice(JoinPoint jp) {
        // 获取方法名
        String name = jp.getSignature().getName();
        System.out.println("[▲Logging]The method " + name + " ends");
    }
    //返回通知,在目标方法执行后执行
    public void returnAdvice(JoinPoint jp , Object result) {
        // 获取方法名
        String name = jp.getSignature().getName();
        System.out.println("[▲Logging]The method " + name + " returns "+result);
    }
    
    //异常通知,在目标方法执行出现异常时执行
    public void exceptionAdvice(JoinPoint jp , Exception e) {
        // 获取方法名
        String name = jp.getSignature().getName();
        System.out.println("[▲Logging]The method " + name + " occours "+e);
    }
    
    //环绕通知,相当于动态代理的全过程
    public Object roundAdvice(ProceedingJoinPoint pjp) {
        //获取方法名
        String name = pjp.getSignature().getName();
        //获取参数
        Object[] args = pjp.getArgs();
        Object result = null;
        try {
            //前置通知
            System.out.println("[▲▲Logging]The method " + name + " begins with " + Arrays.asList(args));
            //执行目标方法
            result = pjp.proceed();
            //返回通知
            System.out.println("[▲▲Logging]The method " + name + " returns "+result);
        } catch (Throwable e) {
            //异常通知
            System.out.println("[▲▲Logging]The method " + name + " occours "+e);
//            e.printStackTrace();
        } finally{
            //后置通知
            System.out.println("[▲▲Logging]The method " + name + " ends");
        }
        return result;
    }
    
}

test
package com.atguigu.spring.test;
import static org.junit.Assert.fail;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.atguigu.spring.xml.ArithmeticCalculator;
public class Aop_xmlTest {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans-xml.xml");
    @Test
    public void testAOP_xml() {
        ArithmeticCalculator atc = (ArithmeticCalculator) ioc.getBean("arithmeticCalculator");
        // 进行加、减、乘、除的运算
        int add = atc.add(10, 2);
        System.out.println(add);
        int sub = atc.sub(10, 2);
        System.out.println(sub);
        int mul = atc.mul(10, 2);
        System.out.println(mul);
        int div = atc.div(10, 2);
        System.out.println(div);
    }
}