标签:url this 失败 interface gpo throw enable intercept glob
同一次业务操作过程中,往往会出现某种操作被重复执行,逻辑上来讲如果只执行一次是最理想的。这里所指的操作特指一些IO操作,比如从数据库中获取登录人的信息,也就是说如果一次请求中包含5个小逻辑,这5个小逻辑包含3次获取用户信息的操作,理想的情况是3次只有一次是从数据库中加载,其余的两次从缓存中获取。
限于非web环境,这里是dubbo实现的微服务。如果是web环境的话解决问题比较简单,因为我们可以充分利用Spring Framwork中提到的三个bean生命周期的特殊来解决:
将老的价格数据迁移成新的价格数据,这里大概是如下的步骤:
上面步骤的价格,规则,关系数据分别属于三个业务对象,自身都具备CRUD的服务接口,这些CRUD都需要记录操作人信息,记录的标准就是接口传入的操作人所持有的token,我们需要将这个token转换成userId,userName之类的信息与价格,规则等信息一并存储。
时序图如下:
由于迁移价格会涉及到多个对象的操作,而操作这些具体业务对象的接口并不支持传具体的userId,userName只支持token,所以不可避免的会在保存价格等信息时各自去根据token查询操作人信息。实测一个价格完成一次数据迁移涉及到获取用户信息的次数多达20+次,效率是比较低,如何去解决呢?
由于我目前实现的微服务是无状态的,也不是web环境,所以上面提到的那些bean的作用域功能就使用不上。
实现类似request作用域的功能,一次请求仅执行一次,其余的请求从缓存中获取结果以提高IO操作效率。
可采用TreadLocal来当缓存,存储频繁读取的数据。增加了CacheContext,获取用户首先从CacheContext中取,如果为空则从数据库加载然后回写到Treadlocal中,下一次再请求用户信息时就可以命中缓存不需要再次从数据库中加载,显然效率得到了质的提升。
时序图如下:
实现步骤如下:
@Service
public class ProductContext {
private static Logger logger = Logger.getLogger(CiaServiceImpl.class);
private ThreadLocal<CiaUserInfo> ciaUserInfoThreadLocal=new ThreadLocal<>();
private void clearCiaUserInfo(){
this.ciaUserInfoThreadLocal.remove();
this.logger.info("清除getTokenInfo缓存成功");
}
public void setCiaUserInfoToCache(CiaUserInfo ciaUserInfo){
this.clearCiaUserInfo();
this.ciaUserInfoThreadLocal.set(ciaUserInfo);
this.logger.info("将getTokenInfo存储到缓存中");
}
public CiaUserInfo getCiaUserInfoFromCache(String token){
CiaUserInfo ciaUserInfo =this.ciaUserInfoThreadLocal.get();
if(null!=ciaUserInfo){
this.logger.info("从缓存中获取到用户信息getTokenInfo");
}
return ciaUserInfo;
}
public void clearAll(){
this.clearCiaUserInfo();
this.logger.info("清除ProductContext的缓存成功");
}
}
public CiaUserInfo getTokenInfo(String token) throws Exception {
CiaUserInfo result = this.productContext.getCiaUserInfoFromCache(token);
if(null!=result){
return result;
}
else {
result=new CiaUserInfo();
}
//...get user from db
this.productContext.setCiaUserInfoToCache(result);
return result;
}
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface LocalCacheContext {
/**
* 是否启动
* @return
*/
boolean enable() default true;
}
@Aspect
public class LocalCacheContextInterceptor {
private Logger logger = LoggerFactory.getLogger(getClass().getName());
@Autowired
private ProductContext productContext;
@Pointcut("execution(* product.service.service.impl.*.*(..))")
public void pointCut() {
}
@After("pointCut()")
public void after(JoinPoint joinPoint) throws ProductServiceException {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method targetMethod = methodSignature.getMethod();
LocalCacheContext localCacheContext= targetMethod.getAnnotation(LocalCacheContext.class);
if(null!=localCacheContext){
this.productContext.clearAll();
}
}
}
@LocalCacheContext
public void migrationPrice(Long priceId) throws ProductServiceException {
this.migrationPriceService.migrationPrice(priceId);
}
标签:url this 失败 interface gpo throw enable intercept glob
原文地址:http://www.cnblogs.com/Leo_wl/p/6112113.html