关于aop:Spring-AOP使用时的一些问题

38次阅读

共计 7107 个字符,预计需要花费 18 分钟才能阅读完成。

在应用 AOP 的时候遇到了一些问题,特此记录一下

首先写一个罕用的 AOP 切片

切片类 AopLog

package com.mantis.aop.aspect;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.mantis.aop.common.util.DataUtil;
import eu.bitwalker.useragentutils.UserAgent;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.BeanPropertyBindingResult;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description: 执行程序 失常程序    Around  Before  Method.invoke   Around  After   AfterReturning
 * 异样程序    Around  Before  Method.invoke   After   AfterThrowing
 * @author: wei.wang
 * @since: 2020/4/4 13:47
 * @history: 1.2020/4/4 created by wei.wang
 */
@Aspect
@Component
public class AopLog {private static Logger logger = LoggerFactory.getLogger(AopLog.class);

    /**
     * 定义切点,切点为 com.smec.fin.controller 包和子包里任意办法的执行和 service 层所有办法的执行
     */
    @Pointcut("execution(public * com.mantis.aop.controller..*.*(..))")
    public void log() {// 定义切点}

    /**
     * 定义切点,切点为 com.smec.fin.controller 包和子包里任意办法的执行和 service 层所有办法的执行
     */
    @Pointcut("execution(public * com.mantis.aop.service.impl..*.*(..))")
    public void log2() {// 定义切点}

    /**
     * 盘绕告诉
     *
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("log2()")
    public Object aroundLog(ProceedingJoinPoint point) throws Throwable {logger.info("开始执行盘绕操作");
        Object result = point.proceed();
        logger.info("执行盘绕操作完结,返回值:{}", result);
        return result;
    }
}

服务类 AopServiceImpl

package com.mantis.aop.service.impl;

import com.mantis.aop.service.AopService;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @Description:
 * @author: wei.wang
 * @since: 2020/10/24 12:45
 * @history: 1.2020/10/24 created by wei.wang
 */
@Service
public class AopServiceImpl implements AopService {


    @Override
    public void testAop(String str) {System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testAop" + str);
        this.testAop2("testFinalMethod");
    }

    @Override
    public void testAop2(String str) {//this.testFinalMethod("testFinalMethod");
        System.out.println("com.mantis.aop.service.AopService.AopServiceImpl." + str);
    }

    public final void testFinalMethod(String str) {System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod" + str);
    }

    public void testFinalMethod2(String str) {System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod" + str);
    }
}

1. 同办法运行问题

在应用 AOP 时咱们发现存在同类中调用时切点生效问题,在执行时咱们发现只执行了 testAop 的切点,testAop2 的切点没有执行,这是因为通过 AOP 代理后的对象都曾经不是原来的对象了,而是退出了加强办法的代理对象,应用代理对象调用时能够执行加强办法,然而这里是应用 this 调用的,也就是 AopServiceImpl,因为不是代理对象就没有加强办法。

2020-10-24 13:31:06.261  INFO 13344 --- [nio-9000-exec-1] com.mantis.aop.controller.AopController  : 办法开始执行
2020-10-24 13:31:06.264  INFO 13344 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog             : 开始执行盘绕操作
com.mantis.aop.service.AopService.AopServiceImpl.testAoptest2
com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod

2020-10-24 13:31:06.274  INFO 13344 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog             : 执行盘绕操作完结,返回值:null

用 @Autowired 或 Resource 引入本身依赖

应用注解办法引入本身代理依赖,留神应用结构的形式会有循环依赖问题

    @Autowired
    AopServiceImpl aopService;

    @Override
    public void testAop(String str) {System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testAop" + str);
        aopService.testAop2("testFinalMethod");
        System.out.println();}
2020-10-24 13:36:33.477  INFO 12528 --- [nio-9000-exec-1] com.mantis.aop.controller.AopController  : 办法开始执行
2020-10-24 13:36:33.480  INFO 12528 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog             : 开始执行盘绕操作
com.mantis.aop.service.AopService.AopServiceImpl.testAoptest2
2020-10-24 13:36:33.488  INFO 12528 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog             : 开始执行盘绕操作
com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod
2020-10-24 13:36:33.488  INFO 12528 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog             : 执行盘绕操作完结,返回值:null

2020-10-24 13:36:33.490  INFO 12528 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog             : 执行盘绕操作完结,返回值:null

开启裸露代理类,AopContext.currentProxy() 形式获取代理类

通过裸露代理类形式,理论原理是把代理类增加到以后申请的 ThreadLocal 外面,而后在应用时从 ThreadLocal 中获取代理类,再调用对应的办法

在主办法上退出 @EnableAspectJAutoProxy(exposeProxy=true),而后从 AOP 上下文中获取代理

    @Override
    public void testAop(String str) {System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testAop" + str);
        AopServiceImpl service = AopContext.currentProxy() != null ? (AopServiceImpl) AopContext.currentProxy() : this;
        service.testAop2("testFinalMethod");
        System.out.println();}
2020-10-24 13:38:31.031  INFO 18828 --- [nio-9000-exec-1] com.mantis.aop.controller.AopController  : 办法开始执行
2020-10-24 13:38:31.035  INFO 18828 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog             : 开始执行盘绕操作
com.mantis.aop.service.AopService.AopServiceImpl.testAoptest2
2020-10-24 13:38:31.047  INFO 18828 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog             : 开始执行盘绕操作
com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod
2020-10-24 13:38:31.048  INFO 18828 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog             : 执行盘绕操作完结,返回值:null

2020-10-24 13:38:31.050  INFO 18828 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog             : 执行盘绕操作完结,返回值:null

2.final 关键字问题

Spring AOP 默认应用 cglib,会生成指标对象的子类代理对象。调用指标对象的办法,实际上是调用代理对象的办法。因为子类可能继承父类的办法,因而个别状况下指标类的办法,代理对象都会有。然而当指标类中某个办法带有 final 关键字时,这个办法不能被重写,因而代理对象中没有这个办法,因而会调用指标对象的办法。

带 final 关键字

因为 testFinalMethod 办法中存在 final 关键字,导致无奈重写,后果代理对象就无奈生成这个办法,因而调用指标对象办法,导致没有被加强

    @Override
    public void testAop(String str) {System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testAop" + str);
        AopServiceImpl service = AopContext.currentProxy() != null ? (AopServiceImpl) AopContext.currentProxy() : this;
        service.testFinalMethod("testFinalMethod");
        System.out.println();}
    
    public final void testFinalMethod(String str) {System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod" + str);
    }
2020-10-24 13:47:46.907  INFO 15204 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog             : 开始执行盘绕操作
com.mantis.aop.service.AopService.AopServiceImpl.testAoptest2
com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethodtestFinalMethod

2020-10-24 13:47:46.916  INFO 15204 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog             : 执行盘绕操作完结,返回值:null

不带 final 关键字

因为 testFinalMethod 办法中不存在 final 关键字,所以失常执行加强。

    @Override
    public void testAop(String str) {System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testAop" + str);
        AopServiceImpl service = AopContext.currentProxy() != null ? (AopServiceImpl) AopContext.currentProxy() : this;
        service.testFinalMethod2("testFinalMethod");
        System.out.println();}
    
    public final void testFinalMethod2(String str) {System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod" + str);
    }
2020-10-24 13:50:51.018  INFO 13532 --- [nio-9000-exec-2] com.mantis.aop.controller.AopController  : 办法开始执行
2020-10-24 13:50:51.021  INFO 13532 --- [nio-9000-exec-2] com.mantis.aop.aspect.AopLog             : 开始执行盘绕操作
com.mantis.aop.service.AopService.AopServiceImpl.testAoptest2
2020-10-24 13:50:51.029  INFO 13532 --- [nio-9000-exec-2] com.mantis.aop.aspect.AopLog             : 开始执行盘绕操作
com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethodtestFinalMethod
2020-10-24 13:50:51.030  INFO 13532 --- [nio-9000-exec-2] com.mantis.aop.aspect.AopLog             : 执行盘绕操作完结,返回值:null

2020-10-24 13:50:51.031  INFO 13532 --- [nio-9000-exec-2] com.mantis.aop.aspect.AopLog             : 执行盘绕操作完结,返回值:null

正文完
 0