1. 使用AOP在不改變原有方法的基礎上對接口方法增強,引入依賴
<!--引入AOP依賴-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!--引入Redis依賴-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2. 自定義注解,在需要統計耗時的接口上添加注解
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface TakeCount { int time() default 60; }
3. 配置redis過期監聽和redis配置類
接口訪問次數可以通過監聽redis對應過期key來獲取對應的訪問次數
@Slf4j public class KeyExpiredListener extends KeyExpirationEventMessageListener { @Autowired @Qualifier("myRedisTemplate") private RedisTemplate redisTemplate; @Autowired private PrjAssignService prjAssignService; public KeyExpiredListener(RedisMessageListenerContainer listenerContainer) { super(listenerContainer); } @Override public void onMessage(Message message, byte[] pattern) { //獲取對應的接口訪問次數 log.info("{}接口在指定時間內被訪問{}次",message,redisTemplate.opsForValue().get(message + ":count")); redisTemplate.delete(message + ":count"); // PrjAssign one = prjAssignService.lambdaQuery().eq(PrjAssign::getId, "67f351605c0afe134e349e6d12434b48").one(); // log.info(JSONUtil.toJsonStr(one)); } }
@Configuration public class RedisConfiguration { @Autowired private RedisConnectionFactory redisConnectionFactory; @Bean public RedisMessageListenerContainer redisMessageListenerContainer() { RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer(); redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory); return redisMessageListenerContainer; } @Bean public KeyExpiredListener keyExpiredListener() { return new KeyExpiredListener(this.redisMessageListenerContainer()); } //配置Redis的字符串序列化,默認的為jdk本身的序列化,存儲時會亂碼 @Bean("myRedisTemplate") @SuppressWarnings("all") public RedisTemplate redisTemplate(RedisConnectionFactory factory){ RedisTemplate<String, Object> template = new RedisTemplate<>(); //key序列化 template.setKeySerializer(new StringRedisSerializer()); //value序列化 template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); //hash的key序列化 template.setHashKeySerializer(new StringRedisSerializer()); //hash的value序列化 template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); template.setConnectionFactory(factory); return template; } }
4. 定義AOP切面
在使用了注解的接口上,會被spring掃描,當方法執行前會先執行doBefore()方法,記錄開始時間訪問次數,方法執行完成后執行doAfter()方法
@Slf4j @Aspect @Component public class TakeCountAspect { @Autowired @Qualifier("myRedisTemplate") private RedisTemplate redisTemplate; //用threadlocal記錄當前線程的開始訪問時間 private ThreadLocal<Long> startTime = new ThreadLocal<>(); @Before("@annotation(takeCount)") public void doBefore(TakeCount takeCount){ //記錄開始時間 startTime.set(System.currentTimeMillis()); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); //記錄請求內容 String url = request.getRequestURL().toString(); //查詢緩存中是否存在key并存儲,存在+1, Boolean absent = redisTemplate.opsForValue().setIfAbsent(url, "num", takeCount.time(), TimeUnit.SECONDS); if (absent){ redisTemplate.opsForValue().set(url + ":count",1); }else { redisTemplate.opsForValue().increment(url + ":count"); } } @After("@annotation(TakeCount)") public void doAfter(JoinPoint point){ log.info("{}訪問耗時為:{}ms",point.getSignature().getName(),(System.currentTimeMillis() - startTime.get())); } }
5. 定義接口方法,在方法上使用注解
/** * 通過id查詢項目任務書 * @param id id * @return R */ @Operation(summary = "通過id查詢", description = "通過id查詢") @GetMapping("/{id}" ) @TakeCount() public R getById(@PathVariable("id" ) String id) { return R.ok(prjAssignService.getByIdAssign(id)); }



浙公網安備 33010602011771號