通过 AOP 打印数据访问层摘要

Spring AOP 的一些核心概念

概念 含义
Aspect 切面
Join Point 连接点,Spring AOP里总是代表一次方法执行
Advice 通知,在连接点执行的动作
Pointcut 切入点,说明如何匹配连接点
Introduction 引入,为现有类型声明额外的方法和属性
Target object 目标对象
AOP proxy AOP 代理对象,可以是 JDK 动态代理,也可以是 CGLIB 代理
Weaving 织入,连接切面与目标对象或类型创建代理的过程

常用注解

  • @EnableAspectJAutoProxy
    开启aspectj的支持,对打@aspectj相关注解的类做一个Proxy
  • @Aspect
    用来声明当前这个类是一个切面,需要说明的是光加aspect还不能变成一个bean,要么使用Javaconfig将类声明成一个bean,要么增加一个@Component注解来将这个bean创建出来
  • @Pointcut
    用来指定Pointcut,具体在代码中体现
  • @Before
    用来指定advice是在方法执行前是执行的
  • @After / @AfterReturning / @AfterThrowing
    不管什么情况,在你结束了之后执行;在你成功返回之后执行;在你报错的时候执行
  • @Around
    把这个方法前后都可以处理,把代码封装到里面
  • @Order
    指定切面的一个执行顺序,order越小,优先级越高

如何打印 SQL

HikariCP
• P6SQL,https://github.com/p6spy/p6spy
使用p6sql库

Alibaba Druid
• 内置 SQL 输出
• https://github.com/alibaba/druid/wiki/Druid中使用log4j2进行日志输出

具体代码

@Aspect     //声明这个类为切面
@Component  //将这个类变成一个bean注入容器
@Slf4j
public class PerformanceAspect {
//    @Around("execution(* geektime.spring.springbucks.repository..*(..))")   用来指定Pointcut  有两种方式  拦截repository下面的类
    @Around("repositoryOps()")
    public Object logPerformance(ProceedingJoinPoint pjp) throws Throwable {
        long startTime = System.currentTimeMillis();   //在方法启动之前记录当前时间
        String name = "-";   //方法名字
        String result = "Y"; //方法执行是否成功
        try {
            name = pjp.getSignature().toShortString();  //取出方法名
            return pjp.proceed();
        } catch (Throwable t) {
            result = "N";
            throw t;
        } finally {
            long endTime = System.currentTimeMillis();   //打印当前时间
            log.info("{};{};{}ms", name, result, endTime - startTime);
        }
    }

    @Pointcut("execution(* geektime.spring.springbucks.repository..*(..))")
    private void repositoryOps() {
    }
}

@Slf4j
@EnableTransactionManagement
@SpringBootApplication
@EnableJpaRepositories
@EnableAspectJAutoProxy   //开启aspectj支持
public class SpringBucksApplication implements ApplicationRunner {
	@Autowired
	private CoffeeRepository coffeeRepository;
	@Autowired
	private CoffeeService coffeeService;
	@Autowired
	private CoffeeOrderService orderService;

	public static void main(String[] args) {
		SpringApplication.run(SpringBucksApplication.class, args);
	}

	@Override
	public void run(ApplicationArguments args) throws Exception {
		log.info("All Coffee: {}", coffeeRepository.findAll());

		Optional<Coffee> latte = coffeeService.findOneCoffee("Latte");
		if (latte.isPresent()) {
			CoffeeOrder order = orderService.createOrder("Li Lei", latte.get());
			log.info("Update INIT to PAID: {}", orderService.updateState(order, OrderState.PAID));
			log.info("Update PAID to INIT: {}", orderService.updateState(order, OrderState.INIT));
		}
	}
}

配置文件:

application.properties配置文件
spring.datasource.driver-class-name=com.p6spy.engine.spy.P6SpyDriver
spring.datasource.url=jdbc:p6spy:h2:mem:testdb
spring.datasource.username=sa
spring.datasource.password=

spring.jpa.hibernate.ddl-auto=none
#spring.jpa.properties.hibernate.show_sql=true  因为使用了P6SQL,所以将jpa的输出SQL属性注释掉
#spring.jpa.properties.hibernate.format_sql=true



spy.properties配置文件
# 单行日志
logMessageFormat=com.p6spy.engine.spy.appender.SingleLineFormat
# 使用Slf4J记录sql
appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 是否开启慢SQL记录
outagedetection=true
# 慢SQL记录标准,单位秒
outagedetectioninterval=2

model层、repository层和service层的代码不变,需要注意的是service层中的使用的Repository是被AOP增强的Repository。
程序执行之后,我们可以看到Repository层方法的调用,使用了多长时间。
另外,对于操作用户的信息的时候,要进行脱敏处理。
在这里插入图片描述

发布了59 篇原创文章 · 获赞 6 · 访问量 963

猜你喜欢

转载自blog.csdn.net/weixin_43790623/article/details/103365385