Skip to content

面试速答(先看这里)

**一句话结论:**通过AOP即可实现,通过AOP对Bean进行代理,在每次执行方法前或者后进行几次计数统计。

60秒标准回答:

通过AOP即可实现,通过AOP对Bean进行代理,在每次执行方法前或者后进行几次计数统计。这个主要就是考虑好如何避免并发情况下不准,以及如何使用AOP实现代理

主要的代码如下

首先我们先自定义一个注解,有了这个注解之后,我们可以在想要统计的方法上加上这个注解

**答题顺序:**结论 → 原理/机制 → 关键流程 → 场景与取舍 → 易错点

回答主线:

  • **要点1:**首先我们先自定义一个注解,有了这个注解之后,我们可以在想要统计的方法上加上这个注解:
  • **要点2:**接下来定义一个切面,来对这个注解进行增强处理:
  • **要点3:**有了以上注解和切面后,只需要在我们想要统计的方法上使用该注解就行了:
  • **要点4:**以上,当test方法被调用时,就会自动统计调用次数。
  • **要点5:**但是需要注意的是,这个统计结果只在内存中有效,如果应用发生重启,就会归零了。

**记忆锚点:**AOP → Bean → AtomicInteger → 我们先自定义一个注解 → 在我们想要统计的方法 → LongAdder

易错提醒:

  • 这个主要就是考虑好如何避免并发情况下不准,以及如何使用AOP实现代理。
  • 但是需要注意的是,这个统计结果只在内存中有效,如果应用发生重启,就会归零了。

加分表达:

  • 如果想要持久化保存,就需要考虑持久化存储了,如存在mysql或者redis中。
  • 另外,如果并发特别高,对统计结果要求没那么精确, 可以用LongAdder替代AtomicInteger

追问准备:

  • 围绕「AOP」:底层原理是什么?使用时有哪些边界和常见坑?
  • 围绕「Bean」:底层原理是什么?使用时有哪些边界和常见坑?
  • 围绕「AtomicInteger」:底层原理是什么?使用时有哪些边界和常见坑?
  • 如果线上出现异常,你会如何定位、验证并规避?

典型回答 ​

通过AOP即可实现,通过AOP对Bean进行代理,在每次执行方法前或者后进行几次计数统计。这个主要就是考虑好如何避免并发情况下不准,以及如何使用AOP实现代理。

主要的代码如下:

首先我们先自定义一个注解,有了这个注解之后,我们可以在想要统计的方法上加上这个注解:

java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author Hollis
**/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MethodCallCount {
    
}

接下来定义一个切面,来对这个注解进行增强处理:

java
@Aspect
@Component
public class MethodCallCounterAspect {

	private Map<String, AtomicInteger> methodCallCountMap = new ConcurrentHashMap<>();

    @Around("@annotation(com.hollis.chuang.java.bagu.MethodCallCount)")
    public Object facade(ProceedingJoinPoint pjp) throws Exception {

        Method method = ((MethodSignature) pjp.getSignature()).getMethod();
        String methodName = method.getName();

        try{
            return pjp.proceed();
        } catch (Throwable e) {
            //异常处理
        } finally{
            //计数+1
            AtomicInteger counter = methodCallCountMap.computeIfAbsent(methodName, k -> new AtomicInteger(0));
            counter.incrementAndGet();
        }
    }

    public int getMethodCallCount(String methodName) {
        AtomicInteger counter = methodCallCountMap.get(methodName);
        return (counter != null) ? counter.get() : 0;
    }
}

有了以上注解和切面后,只需要在我们想要统计的方法上使用该注解就行了:

java
@Service
public class HollisTestServiceImpl implements HollisTestService {

 
    @MethodCallCount
    @Override
    public HollisTestResponse test(HollisTestRequest hollisTestRequest) {
        
    }

以上,当test方法被调用时,就会自动统计调用次数。

但是需要注意的是,这个统计结果只在内存中有效,如果应用发生重启,就会归零了。如果想要持久化保存,就需要考虑持久化存储了,如存在mysql或者redis中。

另外,如果并发特别高,对统计结果要求没那么精确, 可以用LongAdder替代AtomicInteger