Spring-Aop

Spring AOP APIs :: Spring Framework

StandsSpringBoot: 学习

设计模式-代理(Proxy)模式_存在,及合理的博客-CSDN博客

       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

介绍

        AOP(Aspect Oriented Programming):面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术AOP是OOP(面向对象编程)的延续,可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码,使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码。

        AspectJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入

        在程序运行期间,不修改源码对已有方法进行增强。

        减少重复代码,提高开发效率维护方便

Java OOP存在哪些局限性 

        静态化语言:类结构一旦定义,不容易被修改

        侵入性扩展:通过继承和组合组织新的类结构

使用场景

日志

  诊断上下文,如:log4j或logback中的MDC

  辅助信息,如:方法执行时间

统计

  方法调用次数

  执行异常次数

  数据抽样

  数值累加

安防场景

  熔断,如:Netflix Hystrix

  限流和降级:如:Alibaba Sentinel

  认证和授权,如:Spring Security

  监控,如:JMX

性能场景

  缓存,如Spring Cache

  超时控制

 切入点指示器

SpringAOP-切点指示器_存在,及合理的博客-CSDN博客

术语

Joinpoint:是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的必须放在通知方法参数的第一位

Pointcut :切入点是指我们要对哪些 Joinpoint 进行拦截的定义

Introduction:引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方法或 Field。

Target:代理的目标对象

Weaving:是指把增强应用到目标对象来创建新的代理对象的过程。 spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入。

Proxy一个类被 AOP 织入增强后,就产生一个结果代理类。
Aspect  是切入点和通知(引介)的结合

Advice: 所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。 method:用于指定通知类中的增强方法名称 ponitcut-ref:用于指定切入点的表达式的引用 poinitcut:用于指定切入点表达式

通知

拦截到 Joinpoint 之后所要做的事情就是通知。

method:用于指定通知类中的增强方法名称

ponitcut-ref:用于指定切入点的表达式的引用

poinitcut:用于指定切入点表达式

前置通知

  aop:before用于配置前置通知。指定增强的方法在切入点方法之前执行

  利用接入点可以获取方法的相关信息

@Before("pt1()")
public  void beforePrintLog(JoinPoint joinPoint){
    Object[] args = joinPoint.getArgs();
    String kind = joinPoint.getKind();
    Signature signature = joinPoint.getSignature();
    String name = signature.getName();
}

后置通知

  可以获取方法的返回值

  @AfterReturning(value = "pt1()",returning = "result")
  public  void afterReturningPrintLog(Object result){
      System.out.println(result);
   }

异常通

  @AfterThrowing(value = "pt1()" ,throwing = "e")
  public  void afterThrowingPrintLog(Exception e){
  	}

最终通知

  @After("pt1()")
  public  void afterPrintLog(){
    System.out.println("最终通知Logger类中的afterPrintLog方法开始记录日志了。。。");
}

环绕通知

@Around("pt1()")
public Object aroundPringLog(ProceedingJoinPoint pjp){
    Object rtValue = null;
    try{
        Object[] args = pjp.getArgs();
        System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。前置");
        rtValue = pjp.proceed(args);
        System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。后置");

        return rtValue;
    }catch (Throwable t){
        System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。异常");
        throw new RuntimeException(t);
    }finally {
        System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。最终");
    }
}

示例

@Configuration
@Aspect
@Slf4j
public class WebLogAspect {

    @Qualifier("objectMapper")
    @Autowired
    private ObjectMapper mapper;
    private static final Integer PRINT_LOG_SIZE_LIMIT = 1000;

    @Pointcut("execution(* com.du.mons.request..*.*(..))")
    public void webLog() {
    }

    @Before("webLog()")
    public void  beforeInvoke(JoinPoint joinPoint) throws JsonProcessingException {

        logExport(joinPoint,0);
    }


    @After("webLog()")
    public void doAfter() {

        log.debug("======================= Request Done =======================");
        log.debug("");
    }

    @Around("webLog()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws JsonProcessingException {

        Object result  = null;
        try {
            StopWatch sw = StopWatch.createStarted();
            result = proceedingJoinPoint.proceed();
            String resultJson;
            resultJson = mapper.writeValueAsString(result);
            if (resultJson.length() > PRINT_LOG_SIZE_LIMIT) {
                log.trace("Response Args: [{}]", resultJson);
            } else {
                log.debug("Response Args: [{}]", resultJson);
            }
            sw.stop();
            log.debug("Time Elapsed: [{}ms]", sw.getTime(TimeUnit.MILLISECONDS));

        } catch (Exception e) {
            logExport(proceedingJoinPoint,1);
            if (e instanceof ConstraintViolationException){
                ConstraintViolationException constraintViolationException = (ConstraintViolationException) e;
                String message = constraintViolationException.getMessage();
                ResultVO<Object> objectResultVO = new ResultVO<>();
                objectResultVO.setCode(ResultEnumsWarren.PARAMETER_WARREN.getCode());
                objectResultVO.setMsg(message);
                return objectResultVO;
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return result;
    }

    /**
     * 打印 日志 信息
     * @param joinPoint 连接点
     * @param i  1 error, 0 debug
     * @throws JsonProcessingException g
     */
    private void logExport(JoinPoint joinPoint,int i) throws JsonProcessingException {

        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
        HttpServletRequest request = servletRequestAttributes.getRequest();

        if (i == 1) {
            log.error("======================= Request Coming =======================");
            log.error("URL: [{}]", request.getRequestURL().toString());
            log.error("HTTP Method: [{}]", request.getMethod());
            log.error("Class Method: [{}].[{}]",
                    joinPoint.getSignature().getDeclaringTypeName(),
                    joinPoint.getSignature().getName());
        } else {
            log.debug("======================= Request Coming =======================");
            log.debug("URL: [{}]", request.getRequestURL().toString());
            log.debug("HTTP Method: [{}]", request.getMethod());
            log.debug("Class Method: [{}].[{}]",
                    joinPoint.getSignature().getDeclaringTypeName(),
                    joinPoint.getSignature().getName());
        }
        if (MyBeanUtils.isNotEmpty(joinPoint.getArgs())){
            ArrayList<Object> args = new ArrayList<>();

            for (Object arg : joinPoint.getArgs()) {
                if (arg instanceof MultipartFile){
                    continue;
                }
                args.add(arg);
            }
            if (args.size()>0){
                String requestArgs = mapper.writeValueAsString(joinPoint.getArgs());
                if (requestArgs.length() > PRINT_LOG_SIZE_LIMIT) {
                    log.trace("Request Args: [{}]", requestArgs);
                } else {
                    if (i == 1) {
                        log.error("Request Args: [{}]", requestArgs);
                    }else {
                        log.debug("Request Args: [{}]", requestArgs);
                    }
                }
            }
        }
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值