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));
    }

 

 

posted on 2024-04-23 14:48  homle  阅读(282)  评论(0编辑  收藏  举报