AOP详解

什么是AOP
AOP是一个切面编程的思想,就是能够让我们在不影响主业务功能的前提下,
横切扩展新的功能。比如本章演示的切面日志功能,在不影响主业务流程的情况下打印一些日志。

AOP中的术语
aspect(切面):切面由pointcut和advice组成,是横切逻辑定义和连接点定义的组成;
jointpoint(连接点):连接点是应用程序提供给切面插入的地方,可以添加新的方法
advice(增强):是织入到连接点上的一段程序,另外它还拥有连接点的相关信息,advice是我们切面功能的实现,它通知程序新的行为
pointcut(切点):所谓切点就是你所切取的类中的方法,通常使用pointcuts通过正则表达式来把明显的名字和模式进行匹配应用
introduction(引介):一种特殊的增强,允许添加新的方法和属性到类中
target(目标类):是指那些将使用advice的类,一般是指独立的那些商务模型,就是我的advice植入到什么位置
proxy(代理类):一个类被AOP织入增强后,就会产生一个结果类,他是融合了原类和增强逻辑的代理类;使用了proxy的模式。是指应用了advice的对象,看起来和target对象很相似
weaving(织入):织入就是讲增强逻辑添加到目标对象的过程,是指应用aspects到一个target对象创建proxy对象的过程
AOP中的注解
@Apsect:将当前类标识为一个切面;
@Pointcut:定义切点,这里使用的是条件表达式;
@Before:前置增强,就是在目标方法执行之前执行;
@AfterReturning:后置增强,方法退出时执行;
@AfterThrowing:有异常时该方法执行;
@After:最终增强,无论什么情况都会执行;
@Afround:环绕增强;
配置切面日志
主要功能是打印接口中的参数和返回结果信息

引入切面依赖

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.9.2</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.2</version>
    </dependency>

切面日志实现类
@Aspect
@Component
@Slf4j
public class AspectLog {
/**
* 切点
/
@Pointcut(value = "execution(
com.xiao.demo.springmvc.controller..(…))")
public void logPoincut() {

}

@Around(value = "logPoincut()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
    //记录开始时间
    long beginTime = System.currentTimeMillis();

    RequestAttributes ra = RequestContextHolder.getRequestAttributes();
    ServletRequestAttributes sra = (ServletRequestAttributes) ra;
    HttpServletRequest request = sra.getRequest();
    // 获取请求地址
    Object requestPath = request.getRequestURI();
    String ip = getIpAddr(request);
    //格式换开始时间
    String optTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
    //参数
    Object paramObj = joinPoint.getArgs();
    String param = StringUtils.isEmpty(paramObj) ? "无参数" : JSON.toJSONString(paramObj);
    //返回结果
    Object resultObj = joinPoint.proceed();
    String result = StringUtils.isEmpty(resultObj) ? "无返回值" : JSON.toJSONString(resultObj);
    //获取切点方法对象
    MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    Method method = signature.getMethod();
    //获取类名
    String className = joinPoint.getTarget().getClass().getName();
    //获取方法名
    String methodName = method.getName();

    log.info("*****************************************************************************************************************");
    log.info("[访问时间]>>>>>" + optTime);
    log.info("[访问 IP]>>>>>" + ip);
    log.info("[访问路由]>>>>>" + requestPath);
    log.info("[访问方法]>>>>>" + className.concat(".").concat(methodName).concat("()"));
    log.info("[传入参数]>>>>>" + param);
    log.info("[返回参数]>>>>>" + result);
    log.info("[耗费时间]>>>>>" + (System.currentTimeMillis() - beginTime) + " ms");
    log.info("*****************************************************************************************************************\n");
    return resultObj;
}

@AfterThrowing(throwing = "ex", pointcut = "logPoincut()")
public void doRecoveryActions(JoinPoint joinPoint, Throwable ex) {
    long beginTime = System.currentTimeMillis();
    //格式换开始时间
    String optTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());

    RequestAttributes ra = RequestContextHolder.getRequestAttributes();
    ServletRequestAttributes sra = (ServletRequestAttributes) ra;
    HttpServletRequest request = sra.getRequest();
    // 获取请求地址
    Object requestPath = request.getRequestURI();
    String ip = getIpAddr(request);

    //参数
    Object paramObj = joinPoint.getArgs();
    String param = StringUtils.isEmpty(paramObj) ? "无参数" : JSON.toJSONString(paramObj);
    //获取切点方法对象
    MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    Method method = signature.getMethod();
    //获取类名
    String className = joinPoint.getTarget().getClass().getName();
    //获取方法名
    String methodName = method.getName();

    log.error("\n");
    log.error("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
    log.error("[异常时间]>>>>>" + optTime);
    log.error("[访问 IP]>>>>>" + ip);
    log.error("[访问路由]>>>>>" + requestPath);
    log.error("[异常类型]>>>>>" + ex.getClass().getName());
    log.error("[异常方法]>>>>>" + className.concat(".").concat(methodName).concat("()"));
    log.error("[传入参数]>>>>>" + param);
    log.error("[耗费时间]>>>>>" + (System.currentTimeMillis() - beginTime) + " ms");
    log.error("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n");
}

/**
 * 获取IP地址
 */
public String getIpAddr(HttpServletRequest request) {
    String ip = request.getHeader("x-forwarded-for");
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getHeader("Proxy-Client-IP");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getHeader("WL-Proxy-Client-IP");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getRemoteAddr();
    }
    return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
}

}
开启切面编程
在spring-mvc.xml文件中添加如下代码

<bean id="aspectLog" class="com.xiao.demo.springmvc.config.AspectLog"/>
<!--开启切面功能-->
<!--自动为spring容器中那些配置@aspectJ切面的bean创建代理,织入切面-->
<aop:aspectj-autoproxy proxy-target-class="true"/>

运行项目,验证结果
请求接口http://localhost:8089/demo_springmvc/user/select?id=3
在这里插入图片描述
查看控制台输出
在这里插入图片描述
本文只是简单演示如何实现切面日志功能,想要加载其他功能,请自行扩展。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AOP (Aspect-Oriented Programming) around advice is a type of advice that allows you to wrap your target method with additional logic. It is one of the four types of advice in AOP, along with before, after, and after-returning advice. Around advice is more powerful compared to other types of advice because it allows you to have control over the target method's execution. With around advice, you can choose to proceed with the target method's execution, skip it entirely, or modify its behavior by manipulating the input arguments and return value. In AOP frameworks like Spring, you can use around advice by implementing the `ProceedingJoinPoint` interface. This interface provides a `proceed()` method that you can call within your around advice to invoke the target method. By calling `proceed()`, you can continue the execution of the target method. Here's an example of how around advice can be used in AOP: ```java @Around("execution(* com.example.MyService.doSomething(..))") public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable { // Before the target method execution Object result = null; try { // Proceed with the target method execution result = joinPoint.proceed(); // After the target method execution } catch (Exception ex) { // Exception handling } return result; } ``` In this example, the `aroundAdvice` method is annotated with `@Around` to indicate that it is an around advice. It wraps the execution of the `doSomething` method from the `MyService` class. Within the `aroundAdvice` method, you can add additional logic before and after the target method's execution. I hope this explanation helps! Let me know if you have any more questions.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值