前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >深入理解AOP思想

深入理解AOP思想

作者头像
用户11097514
发布2024-05-30 21:31:31
790
发布2024-05-30 21:31:31
举报
文章被收录于专栏:技术分享

AOP

概念 : AOP为Aspect Oriented Programming的缩写, 意思为切面编程。

他是一种可以在不修改原来核心代码的情况下给程序动态统一进增强的一种技术

springAOP : 批量对spring容器中的bean的方法做增强,并且这种增强不会与原来方法中的代码耦合

依赖

代码语言:javascript
复制
<dependency>
	<groupId>org.aspect</groupId>
	<artifactId>aspectjweaver</artifactId>
    <version>1.8.13</version>
</dependency>

快速入门实现

定义切面类

代码语言:javascript
复制
@Component 	//将类交给容器去管理
@Aspect 	//作用 : 告诉Spring容器,这是一个切面类
public class MyAspect{  
}

切入点

代码语言:javascript
复制
@Component 	//将类交给容器去管理
@Aspect 	//作用 : 告诉Spring容器,这是一个切面类
public class MyAspect{  
	
    //定义切入点
    @Pointcut("execution("需要增强的路径地址")")
    public void pt(){}
	
    //在被调用的方法之前执行
    @Before("pt()")		//增强是针对哪些方法
    public void methodbefore(){
       
    }
    
}

aop核心概念

连接点 : 【joinpoint】所谓的连接点就是能够被增强到的点,在spring中 只支持方法类型的连接点

切入点 : 【pointcut】所谓的切入点,就是指被增强的连接点

**通知/增强 :【Advice】 **所谓的通知是指jurisdiction增强的代码

**目标对象 : 【Target】 **被增强的对象就是目标对象

切面: 【Aspect】: 是指切入点 和通知(引介) 的 结合

**代理 : 【Proxy】 **一个类被aop增强后,所产生一个结果的代理类

切入点

  1. **切入点表达式: **

举例:

  1. 切点函数(用的不多)

我们可以在要增强的方法上加上注解。然后使用@annotation来表示对加了什么注解的方法进行增强。

代码语言:javascript
复制
/**
 * 自定义注解
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SystemLog {

    String businessName();
}
  1. 在自定义注解上需要加

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD)

  1. 在需要被注解增强的相关方法上加上我们自定义的注解的注解名就可以实现增强
  2. 在切面类上进行添加切入点等信息

通知

几种通知的分类

代码语言:javascript
复制
package tech.pdai.springframework.aspect;

import org.aspectj.lang.ProceedingJoinPoint;

/**
 * @author pdai
 */
public class LogAspect {

    /**
     * 环绕通知.
     *
     * @param pjp pjp
     * @return obj
     * @throws Throwable exception
     */
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("-----------------------");
        System.out.println("环绕通知: 进入方法");
        Object o = pjp.proceed();
        System.out.println("环绕通知: 退出方法");
        return o;
    }

    /**
     * 前置通知.
     */
    public void doBefore() {
        System.out.println("前置通知");
    }

    /**
     * 后置通知.
     *
     * @param result return val
     */
    public void doAfterReturning(String result) {
        System.out.println("后置通知, 返回值: " + result);
    }

    /**
     * 异常通知.
     *
     * @param e exception
     */
    public void doAfterThrowing(Exception e) {
        System.out.println("异常通知, 异常: " + e.getMessage());
    }

    /**
     * 最终通知.
     */
    public void doAfter() {
        System.out.println("最终通知");
    }

}

环绕通知

如何使用 ?

代码语言:javascript
复制
@Around("pt()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("-----------------------");
        System.out.println("环绕通知: 进入方法前");
        Object o = pjp.proceed();
        System.out.println("环绕通知: 退出方法后");
        return o;
    }

注意点 : 如果目标方法有返回值 ,那么对应的切面类中的环绕通知的方法也必须有返回值

AspectJ注解方式

基于XML的声明式AspectJ存在一些不足,需要在Spring配置文件配置大量的代码信息,为了解决这个问题,Spring 使用了@AspectJ框架为AOP的实现提供了一套注解。

注解名称

解释

@Aspect

用来定义一个切面。

@pointcut

用于定义切入点表达式。在使用时还需要定义一个包含名字和任意参数的方法签名来表示切入点名称,这个方法签名就是一个返回值为void,且方法体为空的普通方法。

@Before

用于定义前置通知,相当于BeforeAdvice。在使用时,通常需要指定一个value属性值,该属性值用于指定一个切入点表达式(可以是已有的切入点,也可以直接定义切入点表达式)。

@AfterReturning

用于定义后置通知,相当于AfterReturningAdvice。在使用时可以指定pointcut / value和returning属性,其中pointcut / value这两个属性的作用一样,都用于指定切入点表达式。

@Around

用于定义环绕通知,相当于MethodInterceptor。在使用时需要指定一个value属性,该属性用于指定该通知被植入的切入点。

@After-Throwing

用于定义异常通知来处理程序中未处理的异常,相当于ThrowAdvice。在使用时可指定pointcut / value和throwing属性。其中pointcut/value用于指定切入点表达式,而throwing属性值用于指定-一个形参名来表示Advice方法中可定义与此同名的形参,该形参可用于访问目标方法抛出的异常。

@After

用于定义最终final 通知,不管是否异常,该通知都会执行。使用时需要指定一个value属性,该属性用于指定该通知被植入的切入点。

@DeclareParents

用于定义引介通知,相当于IntroductionInterceptor (不要求掌握)。



获取被增强方法相关信息

我们实际对方法进行增强时往往还需要获取到被增强方法的相关信息,比如 : 方法名,参数,返回值,异常信息….

我们除了在环绕通知外的所有通知方法中增加一个JoinPoint类型的参数。这个参数封装了被增强方法的相关信息 。我们还可以通过这个参数获取到除了异常对象 和返回值 之外的所有信息。

代码语言:javascript
复制


//对于controller层的方法增强
private void handleBefore(ProceedingJoinPoint joinPoint) {
    ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    HttpServletRequest request = requestAttributes.getRequest();
    //获取被增强方法上的注解对象
    SystemLog systemLog = getSystemLog(joinPoint);
    log.info("============Start============");
    // 打印请求 URL
    log.info("URL            : {}",request.getRequestURL());
    // 打印描述信息
    log.info("BusinessName   : {}",systemLog.businessName());
    // 打印 Http method
    log.info("HTTP Method    : {}",request.getMethod());
    // 打印调用 controller 的全路径以及执行方法
    log.info("Class Method   : {}.{}",joinPoint.getSignature().getDeclaringTypeName(),((MethodSignature) joinPoint.getSignature()).getName());
    // 打印请求的 IP
    log.info("IP             : {}",request.getRemoteHost());
    // 打印请求入参
    log.info("Request Args   : {}", JSON.toJSONString(joinPoint.getArgs()) );

}
代码语言:javascript
复制
//对于service层的方法增强
private void handleBefore(ProceedingJoinPoint joinPoint) {
	        String className = joinPoint.getSignature().getDeclaringTypeName();
        System.out.println("获取 类名:  " + className);

        String methodName = joinPoint.getSignature().getName();
        System.out.println("获取方法名 : "  + methodName);

        Object[] args = joinPoint.getArgs();
        System.out.println("获取参数;" + Arrays.toString(args));
        System.out.println("获取参数(转为json格式);" + JSON.toJSONString(args));
    

}

异常

多切面增强顺序

通过@Order的大小来规定多个切面的顺序

参考学习说明:

视频学习 : 三更springAOP

相关资料参考 :https://pdai.tech/md/spring/spring-x-framework-aop.html

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-03-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • AOP
    • 依赖
      • 快速入门实现
        • 定义切面类
        • 切入点
      • aop核心概念
        • 切入点
        • 通知
        • 环绕通知
        • AspectJ注解方式
      • 获取被增强方法相关信息
        • 多切面增强顺序
          • 参考学习说明:
          相关产品与服务
          容器服务
          腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档