29.【Spring基于注解的AOP配置】

Spring基于注解的AOP配置

操作步骤

  1. 配置spring创建容器时要扫描的包

  2. 对工具类和实现类加上注解

  3. 标注切面和切点

@Component("logger")
@Aspect// 表示当前类是一个切面
public class Logger {

    @Pointcut("execution(* cn.luis.service.impl.*.*(..))")
    private void pt() {}\
     ...
}
  1. 标注通知类型
  2. 配置spring开启注解AOP的支持
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

配置文件

<?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">

    <!-- 配置spring创建容器时要扫描的包-->
    <context:component-scan base-package="cn.luis"></context:component-scan>

    <!-- 配置spring开启注解AOP的支持 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

四种常用通知

注意:此方式的通知存在执行顺序问题

账户的业务层实现类

@Service("accountService")
public class AccountServiceImpl implements IAccountService{

    @Override
    public void saveAccount() {
        System.out.println("执行了保存");
        //int i = 1/0;
    }
}

记录日志的工具类

@Component("logger")
@Aspect// 表示当前类是一个切面
public class Logger {

    @Pointcut("execution(* cn.luis.service.impl.*.*(..))")
    private void pt() {}

    /**
     * 前置通知
     */
    @Before("pt()")
    public void beforePrintLog() {
        System.out.println("前置通知开始记录日志...");
    }

    /**
     * 后置通知
     */
    @AfterReturning("pt()")
    public void aftereReturnPrintLog() {
        System.out.println("后置通知开始记录日志...");
    }

    /**
     * 异常通知
     */
    @AfterThrowing("pt()")
    public void afterThrowingPrintLog() {
        System.out.println("异常通知开始记录日志...");
    }

    /**
     * 最终通知
     */
    @After("pt()")
    public void afterPrintLog() {
        System.out.println("最终通知开始记录日志...");
    }
}

测试类

public class AOPTest {

    public static void main(String[] args) {
        // 1.获取容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        // 2.获取对象
        IAccountService as = (IAccountService) ac.getBean("accountService");
        // 3.执行方法
        as.saveAccount();
    }
}

结果:

  • 存在执行顺序问题
前置通知开始记录日志...
执行了保存
最终通知开始记录日志...
后置通知开始记录日志...

环绕通知

账户的业务层实现类

@Service("accountService")
public class AccountServiceImpl implements IAccountService{

    @Override
    public void saveAccount() {
        System.out.println("执行了保存");
        //int i = 1/0;
    }
}

记录日志的工具类

@Component("logger")
@Aspect// 表示当前类是一个切面
public class Logger {

    @Pointcut("execution(* cn.luis.service.impl.*.*(..))")
    private void pt() {}

    @Around("pt()")
    public Object aroundPrintLog(ProceedingJoinPoint pjp) {
        Object rtValue = null;
        try {
            // 1.得到方法执行所需的参数
            Object[] args = pjp.getArgs();
            System.out.println("环绕通知开始记录日志...前置");
            // 2.明确调用业务层方法(切入点方法),这里的异常要用 【throws Throwable】
            rtValue = pjp.proceed(args);
            System.out.println("环绕通知开始记录日志...后置");
            // 3.返回值
            return rtValue;
        } catch (Throwable t) {
            System.out.println("环绕通知开始记录日志...异常");
            // 4.抛异常
            throw new RuntimeException(t);
        } finally {
            System.out.println("环绕通知开始记录日志...最终");
        }

    }
}

测试类

public class AOPTest {

    public static void main(String[] args) {
        // 1.获取容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        // 2.获取对象
        IAccountService as = (IAccountService) ac.getBean("accountService");
        // 3.执行方法
        as.saveAccount();
    }
}

结果:

  • 无顺序问题
环绕通知开始记录日志...前置
执行了保存
环绕通知开始记录日志...后置
环绕通知开始记录日志...最终

不使用xml的配置方式

src -- main -- java下创建config包,创建SpringConfiguration

在测试类中要修改容器

 ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);

创建配置类

package config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration //指定当前类为配置类
@ComponentScan("cn.luis") // 指定spring在创建容器时要扫描的包
@EnableAspectJAutoProxy // 开启注解AOP的支持
public class SpringConfiguration {
}

测试类

package cn.luis.test;

import cn.luis.service.IAccountService;
import config.SpringConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AOPTest {

    public static void main(String[] args) {
        // 1.获取容器
        ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);
        // 2.获取对象
        IAccountService as = (IAccountService) ac.getBean("accountService");
        // 3.执行方法
        as.saveAccount();
    }
}

结果:

环绕通知开始记录日志...前置
执行了保存
环绕通知开始记录日志...后置
环绕通知开始记录日志...最终
发布了36 篇原创文章 · 获赞 14 · 访问量 3586

猜你喜欢

转载自blog.csdn.net/qq_39720594/article/details/105333170
今日推荐