Spring第六章:AOP(Aspect,自定义注解)

时间:2023-02-10 13:22:30

1.AOP方式

  1.1 Schema-based 方式(上篇有写)  

  1.2.AspectJ

    1.2.1 每个通知不需要实现接口或类

    1.2.2 配置 spring 配置文件是在<aop:config>的子标签<aop:aspect>中配置

  AOP配置元素 | 描述 
  ------------ | -------------
  `<aop:advisor>` | 定义AOP通知器
  `<aop:after>`  | 定义AOP后置通知(不管该方法是否执行成功)
  `<aop:after-returning>` | 在方法成功执行后调用通知
  `<aop:after-throwing>` | 在方法抛出异常后调用通知
  `<aop:around>` | 定义AOP环绕通知
  `<aop:aspect>` | 定义切面
  `<aop:aspect-autoproxy>` | 定义`@AspectJ`注解驱动的切面
  `<aop:before>` | 定义AOP前置通知
  `<aop:config>` | 顶层的AOP配置元素,大多数的<aop:*>包含在<aop:config>元素内
  `<aop:declare-parent>` | 为被通知的对象引入额外的接口,并透明的实现
  `<aop:pointcut>` | 定义切点

 

    1.2.3 使用AspectJ方式配置

      1.2.3.1 applicationContext.xml 
<?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"
        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">

    <!-- 配置 Demo 类,测试使用 -->
    <bean id="demo" class="com.suncl.test.Demo"></bean>
    <bean id="myadvice" class="com.suncl.model.MyAdvice" ></bean>
    <aop:config>
        <aop:aspect ref="myadvice">
            <aop:pointcut expression="execution(* com.suncl.test.Demo.demo1(..)) " id="mypoint"/>
            <!--执行前置通知-->
            <aop:before method="beforeLog" pointcut-ref="mypoint" />
            <!-- <aop:after/> 后置通知,是否出现异常都执行 -->
            <aop:after method="afterLog" pointcut-ref="mypoint"/>
            <!--<aop:after-returing/> 后置通知,只有当切点正确执行时执行-->
            <aop:after-returning method="afterReturningLog"  pointcut-ref="mypoint"/>
            <!-- <aop:after-throwing 后置通知,只有当切点错误执行的时候执行-->
            <aop:after-throwing method="afterThrowingLog" pointcut-ref="mypoint"/>
            <!--环绕通知-->
            <aop:around method="aroundLog" pointcut-ref="mypoint"  />
        </aop:aspect>
    </aop:config>
</beans>
      1.2.3.2实体类
package com.suncl.test;

/**
 * Created by SCL-PC on 2019/2/28.
 */
public class Demo {

    public void demo(){
        System.out.println("执行了demo方法");
    }

    public void demo1(String a ,int b){
        System.out.println("执行了demo1111方法");
        //用来验证出现错误的时候切点执行情况
//        int i = 5/0;
    }


}
package com.suncl.model;

import org.aspectj.lang.ProceedingJoinPoint;

/**
 * Created by SCL-PC on 2019/3/3.
 */
public class MyAdvice {

    public void beforeLog() {
        System.out.println("开始执行前置通知  日志记录");
    }
    //    方法执行完后通知
    public void afterLog() {
        System.out.println("开始执行后置通知 日志记录");
    }
    //    执行成功后通知
    public void afterReturningLog() {
        System.out.println("方法成功执行后通知 日志记录");
    }
    //    抛出异常后通知
    public void afterThrowingLog() {
        System.out.println("方法抛出异常后执行通知 日志记录");
    }

    //    环绕通知
    public Object aroundLog(ProceedingJoinPoint joinpoint) {
        Object result = null;
        try {
            System.out.println("环绕通知开始 日志记录");
            long start = System.currentTimeMillis();

            //有返回参数 则需返回值
            result =  joinpoint.proceed();

            long end = System.currentTimeMillis();
            System.out.println("总共执行时长" + (end - start) + " 毫秒");
            System.out.println("环绕通知结束 日志记录");
        } catch (Throwable t) {
            System.out.println("出现错误");
        }
        return result;
    }

}

 

        1.2.3.3测试类
package com.suncl.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created by SCL-PC on 2019/2/28.
 */
public class Test {


    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
         Demo demo = ac.getBean("demo",Demo.class);
        demo.demo1("a",1);
    }


}

 

      1.2.3.4运行结果
开始执行前置通知  日志记录
环绕通知开始 日志记录
执行了demo1111方法
总共执行时长16 毫秒
环绕通知结束 日志记录
方法成功执行后通知 日志记录
开始执行后置通知 日志记录

Process finished with exit code 0

 

 

   1.3 自定义注解(基于AspectJ)  

    1.3.1 每个通知不需要实现接口或类

    1.3.2 使用自动以注解方式配置

      1.3.2.1 applicationContext.xml 
<?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">

    <!--标识哪些类需要扫描注解-->
    <context:component-scan base-package="com.suncl"></context:component-scan>

    <!--使用配置注解,首先我们要将切面在spring上下文中声明成自动代理bean-->
    <aop:aspectj-autoproxy />

</beans>
      1.3.2.2实体类
package com.suncl.model;

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

/**
 * Created by SCL-PC on 2019/3/3.
 */
@Component
@Aspect
public class MyAdvice {

    // 配置切点 及要传的参数
    @Pointcut(" execution(* com.suncl.test.Demo.demo1(..)) ")
    public void pointCut()
    {

    }

    @Before("pointCut()")
    public void beforeLog() {
        System.out.println("开始执行前置通知  日志记录");
    }

    //    方法执行完后通知
    @After("pointCut()")
    public void afterLog() {
        System.out.println("开始执行后置通知 日志记录");
    }

    //    执行成功后通知
    @AfterReturning("pointCut()")
    public void afterReturningLog() {
        System.out.println("方法成功执行后通知 日志记录");
    }

    //    抛出异常后通知
    @AfterThrowing("pointCut()")
    public void afterThrowingLog() {
        System.out.println("方法抛出异常后执行通知 日志记录");
    }

    //    环绕通知
    @Around("pointCut()")
    public Object aroundLog(ProceedingJoinPoint joinpoint) {
        Object result = null;
        try {
            System.out.println("环绕通知开始 日志记录");
            long start = System.currentTimeMillis();

            //有返回参数 则需返回值
            result =  joinpoint.proceed();

            long end = System.currentTimeMillis();
            System.out.println("总共执行时长" + (end - start) + " 毫秒");
            System.out.println("环绕通知结束 日志记录");
        } catch (Throwable t) {
            System.out.println("出现错误");
        }
        return result;
    }

}
 
package com.suncl.test;

import org.springframework.stereotype.Component;

/**
 * Created by SCL-PC on 2019/2/28.
 */
@Component
public class Demo {

    public void demo(){
        System.out.println("执行了demo方法");
    }

    public void demo1(String a ,int b){
        System.out.println("执行了demo1111方法");
        //用来验证出现错误的时候切点执行情况
//        int i = 5/0;
    }


}
       1.3.2.3测试类
package com.suncl.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created by SCL-PC on 2019/2/28.
 */
public class Test {


    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
         Demo demo = ac.getBean("demo",Demo.class);
        demo.demo1("a",1);
    }


}
    1.3.2.4运行结果

 

环绕通知开始 日志记录
开始执行前置通知  日志记录
执行了demo1111方法
总共执行时长31 毫秒
环绕通知结束 日志记录
开始执行后置通知 日志记录
方法成功执行后通知 日志记录

Process finished with exit code 0

以上代码地址:链接:https://pan.baidu.com/s/1xRWt4ndOAZfVJ_YER-aO1w  提取码:jw84