AOP&面向切面编程

简介: AOP&面向切面编程

 定义

面向切面编程。Aspect

好处

业务型代码和非业务型代码 解耦。

在不改变原有业务代码的基础上做增强!

入门操作

1、导入依赖

<!--引入AOP注解-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

image.gif

2、编写切面类

XxxAspect

3、在类头上

加注解

@Aspet

@Component

4、方法头上

加注解

@Around(xxxxxx)

指定要增强的方法有哪些,划定范围

通知类型

@Around

目标方法执行前通知

目标方法执行后通知,有异常则不会执行

@Aspect
@Component
@Slf4j
public class MyAspect {
    //环绕通知
    @Around("execution(* com.itheima.springboot_web.service.*.*(..))")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        log.info("around before ...");
        //调用目标对象的原始方法执行
        Object result = proceedingJoinPoint.proceed();
        //原始方法如果执行时有异常,环绕通知中的后置代码不会在执行了
        log.info("around after ...");
        return result;
    }
}

image.gif

@Before

目标方法执行前通知

@Aspect
@Component
@Slf4j
public class MyAspect {
    //前置通知
    @Before("execution(* com.itheima.springboot_web.service.*.*(..))")
    public void before(JoinPoint joinPoint){
        log.info("before ...");
    }
}

image.gif

@AfterReturning

目标方法返回后通知,有异常则不会执行

@Aspect
@Component
@Slf4j
public class MyAspect {
    //返回后通知(程序在正常执行的情况下,会执行的后置通知)
    @AfterReturning("execution(* com.itheima.springboot_web.service.*.*(..))")
    public void afterReturning(JoinPoint joinPoint){
        log.info("afterReturning ...");
    }
}

image.gif

@After

目标方法后置通知,有无异常都会执行!

@Aspect
@Component
@Slf4j
public class MyAspect {
    //后置通知
    @After("execution(* com.itheima.springboot_web.service.*.*(..))")
    public void after(JoinPoint joinPoint){
        log.info("after ...");
    }
}

image.gif

@AfterThrowing

有异常时才会通知

@Aspect
@Component
@Slf4j
public class MyAspect {
    //异常通知(程序在出现异常的情况下,执行的后置通知)
    @AfterThrowing("execution(* com.itheima.springboot_web.service.*.*(..))")
    public void afterThrowing(JoinPoint joinPoint){
        log.info("afterThrowing ...");
    }
}

image.gif

通知顺序

默认按照类名排序

@Order(数字) 数字越小越优先执行

切入点表达式

execution(权限 返回值 多级报名.类名.方法名(形参列表))

execution(* com.itheima.service..(..))

符号含义

*可以代表:

任意一个形参

任意一个返回值

任意一个方法名

任意一个类名

任意一个包名

..可以代表:

任意多个参数

任意多级包名

提取切入点表达式

@PointCut("execution(* com.. * . *(..)")

注意事项

可以使用&& || !

注解实现切入点表达式

1、定义一个注解

package com.zsh.springboot_web.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
}

image.gif

2、@annotation(自定义注解全类名)

package com.zsh.springboot_web.aspect;
import com.alibaba.fastjson.JSONObject;
import com.itheima.springboot_web.mapper.OperateLogMapper;
import com.itheima.springboot_web.pojo.OperateLog;
import com.itheima.springboot_web.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Arrays;
@Aspect
@Component
@Slf4j
public class LogAspect {
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private OperateLogMapper operateLogMapper;
    @Around("@annotation(com.itheima.springboot_web.annotation.Log)")
    public Object log(ProceedingJoinPoint pjp) throws Throwable {
        // 操作人ID - 当前登录员工ID
        // 获取请求头中的jwt令牌,解析令牌
        String jwt = request.getHeader("token");
        Claims claims = JwtUtils.parseJWT(jwt);
        Integer operateUser = (Integer) claims.get("id");
        // 操作时间
        LocalDateTime operateTime = LocalDateTime.now();
        // 操作类名
        String className = pjp.getTarget().getClass().getName();
        // 操作方法名
        String methodName = pjp.getSignature().getName();
        // 操作方法参数
        Object[] args = pjp.getArgs();
        String methodParams = Arrays.toString(args);
        long begin = System.currentTimeMillis();
        // 调用原始目标方法运行
        Object result = pjp.proceed();
        long end = System.currentTimeMillis()
        //方法返回值
        String returnValue = JSONObject.toJSONString(result);
        //操作耗时
        Long costTime = end - begin;
        //记录操作日志
        OperateLog operateLog = new OperateLog(null,operateUser,operateTime,className,methodName,methodParams,returnValue,costTime);
        operateLogMapper.insert(operateLog);
        log.info("AOP记录操作日志: {}" , operateLog);
        return result;
    }
}

image.gif

3、在需要被增强的方法上加入注解

package com.zsh.springboot_web.service.impl;
import com.itheima.springboot_web.annotation.Log;
import com.itheima.springboot_web.mapper.DeptMapper;
import com.itheima.springboot_web.mapper.EmpMapper;
import com.itheima.springboot_web.pojo.Dept;
import com.itheima.springboot_web.service.DeptLogService;
import com.itheima.springboot_web.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
@Service
public class DeptServiceImpl implements DeptService {
    @Autowired
    private DeptMapper deptMapper;
    @Autowired
    private EmpMapper empMapper;
    @Autowired
    private DeptLogService deptLogService;
    @Override
    public List<Dept> depts() {
        List<Dept> depts = deptMapper.depts();
        return depts;
    }
    /*
    * rollbackfor:默认为运行时异常回滚:RuntimeException.class
    *             可以赋值为Exception.class
    * */
    @Transactional(rollbackFor = Exception.class)   // 方法开启事务,方法内没有任何异常
    @Override
    @Log
    public void deleteById(Integer id) {
        try {
            // 部门删除
            deptMapper.deleteById(id);
            // 删除该部门的员工
            empMapper.deleteDeptId(id);
            int i = 3/0;
        }finally {
            // 记录日志
            deptLogService.add(id);
        }
    }
    @Override
    @Log
    public void add(Dept dept) {
        dept.setCreateTime(LocalDateTime.now());
        dept.setUpdateTime(LocalDateTime.now());
        deptMapper.add(dept);
    }
    @Override
    public Dept findById(Integer id) {
        Dept dept = deptMapper.findById(id);
        return dept;
    }
    @Override
    @Log
    public void update(Dept dept) {
        dept.setUpdateTime(LocalDateTime.now());
        deptMapper.update(dept);
    }
}

image.gif


相关文章
|
3月前
Micronaut AOP与代理机制:实现应用功能增强,无需侵入式编程的秘诀
AOP(面向切面编程)能够帮助我们在不修改现有代码的前提下,为应用程序添加新的功能或行为。Micronaut框架中的AOP模块通过动态代理机制实现了这一目标。AOP将横切关注点(如日志记录、事务管理等)从业务逻辑中分离出来,提高模块化程度。在Micronaut中,带有特定注解的类会在启动时生成代理对象,在运行时拦截方法调用并执行额外逻辑。例如,可以通过创建切面类并在目标类上添加注解来记录方法调用信息,从而在不侵入原有代码的情况下增强应用功能,提高代码的可维护性和可扩展性。
81 1
|
1月前
|
安全 Java 编译器
什么是AOP面向切面编程?怎么简单理解?
本文介绍了面向切面编程(AOP)的基本概念和原理,解释了如何通过分离横切关注点(如日志、事务管理等)来增强代码的模块化和可维护性。AOP的核心概念包括切面、连接点、切入点、通知和织入。文章还提供了一个使用Spring AOP的简单示例,展示了如何定义和应用切面。
144 1
什么是AOP面向切面编程?怎么简单理解?
|
1月前
|
XML Java 开发者
论面向方面的编程技术及其应用(AOP)
【11月更文挑战第2天】随着软件系统的规模和复杂度不断增加,传统的面向过程编程和面向对象编程(OOP)在应对横切关注点(如日志记录、事务管理、安全性检查等)时显得力不从心。面向方面的编程(Aspect-Oriented Programming,简称AOP)作为一种新的编程范式,通过将横切关注点与业务逻辑分离,提高了代码的可维护性、可重用性和可读性。本文首先概述了AOP的基本概念和技术原理,然后结合一个实际项目,详细阐述了在项目实践中使用AOP技术开发的具体步骤,最后分析了使用AOP的原因、开发过程中存在的问题及所使用的技术带来的实际应用效果。
68 5
|
3月前
Micronaut AOP与代理机制:实现应用功能增强,无需侵入式编程的秘诀
【9月更文挑战第9天】AOP(面向切面编程)通过分离横切关注点提高模块化程度,如日志记录、事务管理等。Micronaut AOP基于动态代理机制,在应用启动时为带有特定注解的类生成代理对象,实现在运行时拦截方法调用并执行额外逻辑。通过简单示例展示了如何在不修改 `CalculatorService` 类的情况下记录 `add` 方法的参数和结果,仅需添加 `@Loggable` 注解即可。这不仅提高了代码的可维护性和可扩展性,还降低了引入新错误的风险。
54 13
|
2月前
|
Java 容器
AOP面向切面编程
AOP面向切面编程
48 0
|
4月前
|
XML Java 数据格式
Spring5入门到实战------11、使用XML方式实现AOP切面编程。具体代码+讲解
这篇文章是Spring5框架的AOP切面编程教程,通过XML配置方式,详细讲解了如何创建被增强类和增强类,如何在Spring配置文件中定义切入点和切面,以及如何将增强逻辑应用到具体方法上。文章通过具体的代码示例和测试结果,展示了使用XML配置实现AOP的过程,并强调了虽然注解开发更为便捷,但掌握XML配置也是非常重要的。
Spring5入门到实战------11、使用XML方式实现AOP切面编程。具体代码+讲解
|
4月前
|
Java Spring XML
掌握面向切面编程的秘密武器:Spring AOP 让你的代码优雅转身,横切关注点再也不是难题!
【8月更文挑战第31天】面向切面编程(AOP)通过切面封装横切关注点,如日志记录、事务管理等,使业务逻辑更清晰。Spring AOP提供强大工具,无需在业务代码中硬编码这些功能。本文将深入探讨Spring AOP的概念、工作原理及实际应用,展示如何通过基于注解的配置创建切面,优化代码结构并提高可维护性。通过示例说明如何定义切面类、通知方法及其应用时机,实现方法调用前后的日志记录,展示AOP在分离关注点和添加新功能方面的优势。
71 0
|
5月前
|
Java Spring 容器
Spring问题之Spring AOP是如何实现面向切面编程的
Spring问题之Spring AOP是如何实现面向切面编程的
|
4月前
|
监控 安全 数据库
面向方面编程(AOP)的概念
【8月更文挑战第22天】
89 0
|
4月前
|
XML Java 数据库
Spring5入门到实战------10、操作术语解释--Aspectj注解开发实例。AOP切面编程的实际应用
这篇文章是Spring5框架的实战教程,详细解释了AOP的关键术语,包括连接点、切入点、通知、切面,并展示了如何使用AspectJ注解来开发AOP实例,包括切入点表达式的编写、增强方法的配置、代理对象的创建和优先级设置,以及如何通过注解方式实现完全的AOP配置。