AOP实战

2019-03-06  本文已影响0人  packet

想用AOP做一个缓存。虽然看起来简单,但真正做完还是有些收获。

@RestController
public class AccountController {

    @Autowired
    private AccountService accountService;


    @RequestMapping("/query")
    public long query(@RequestParam(required = false) String userId) {
        return accountService.queryMoney(userId);
    }

}

@Service
public class AccountService {

    @Cache
    public long queryMoney(String userId) {
        try {
            System.out.println("start query money of " + userId);
            Thread.sleep(5000); // 模拟数据库查询
            long money = ThreadLocalRandom.current().nextLong(1000);
            System.out.println(userId + "->" + money);
            return money;
        } catch (Exception e) {
            e.printStackTrace();
            return -1;
        }
    }
}

读操作不能每次都查询,所以需要缓存。
先看下基础类

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface Cache {
}

public class Money {

    private long num;

    private long ttl;

    public Money(long num, long ttl) {
        this.num = num;
        this.ttl = ttl;
    }

    public long getNum() {
        return num;
    }

    public void setNum(long num) {
        this.num = num;
    }

    public long getTtl() {
        return ttl;
    }

    public void setTtl(long ttl) {
        this.ttl = ttl;
    }
}

再看最重要的切面类:

@Component
@Aspect
public class WorkAspect {

    private Map<String, Money> cache = new ConcurrentHashMap<>();

    @Pointcut("@annotation(com.example.aop.Cache)")
    public void point() {
    }

    @Around("point()")
    public long query(ProceedingJoinPoint joinPoint) {
        String userId = (String) joinPoint.getArgs()[0]; // 检查参数
        if (StringUtils.isEmpty(userId)) {
            return -1;
        }
        Money money = cache.get(userId);
        if (money != null && System.currentTimeMillis() < money.getTtl()) {
            return money.getNum();
        }
        long num = -1;
        try {
            num = (long) joinPoint.proceed();
            cache.put(userId, new Money(num, System.currentTimeMillis() + 60000));
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return num;
    }
}

这个业务背景需要注意,因为查询的是钱,所以要求当金钱数量变化的时候,缓存中的数据需要淘汰或者更新。

上一篇下一篇

猜你喜欢

热点阅读