pingssys-dubbo本地存根(stub)缓存前置(redis缓存)

1.背景

  • 本人在开发pingss-sys脚手架(项目地址)的时候,使用了jwt无状态权限认证。每个用户请求,都需要对比用户的token,是否有权限访问对应的资源,访问相当频繁,如果每次都访问provider,将耗费相当多的资源,本人觉得应该使用缓存。由于使用了微服务架构,缓存的用户数据可能会有多个客户端都访问,考虑使用redis分布式缓存。
  • 环境springboot-2.1.1 + dubbo-2.6.5
  • 这种访问非常频繁的数据,放到java堆缓存,效率更高。虽然多个微服务不能共享,但是每个服务向provider查一次,也不会使用太多资源。考虑更换成java堆缓存

2.步骤

2.1.本地service
  • 刚开始只有一个权限项目,为了简单,使用了本地UserServiceImpl,所有请求先在访问本地缓存,没有在去provider获取。
  • 问题:这种方式,基本没有问题,但是在项目多了以后,非常的不美观,每个项目都有一个相同的UserServiceImpl文件。
/**
 *********************************************************
 ** @desc  : 用户管理
 ** @author  Pings
 ** @date    2019/1/25
 ** @version v1.0
 * *******************************************************
 */
@Component
@CacheConfig(cacheNames="user")
public class IUserServiceImpl implements UserService {

    public static final String USER_KEY_PREFIX = "user::";

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Reference(version = "${sys.service.version}")
    private UserService userService;

    @Override
    public User getById(int id) {
        return this.userService.getById(id);
    }

    @Override
    @Cacheable
    public User getByUserName(String userName) {
        return this.userService.getByUserName(userName);
    }

    @Override
    public IPage<User> findPage(IPage<User> page, User entity) {
        IPage<User> rst = this.userService.findPage(page, entity);
        return rst;
    }

    @Override
    public List<User> findAll() {
        return this.userService.findAll();
    }

    @Override
    public User save(User user) {
        //**删除缓存
        this.redisTemplate.delete(USER_KEY_PREFIX + user.getUserName());

        user = this.userService.save(user);

        return user;
    }

    @Override
    public int deleteById(int id) {
        //**删除缓存
        User user = this.userService.getById(id);
        this.redisTemplate.delete(USER_KEY_PREFIX + user.getUserName());

        return this.userService.deleteById(id);
    }

    @Override
    public int allotRole(int id, int[] roles, int currentUserId) {
        //**删除缓存
        User user = this.userService.getById(id);
        this.redisTemplate.delete(USER_KEY_PREFIX + user.getUserName());

        return this.userService.allotRole(id, roles, currentUserId);
    }
}
2.2.dubbo本地存根stub
  • dubbo提供了本地存根stub的,在接口旁边写一个stub,并在provider的接口中配置后,dubbo会调用它的构造方法,并传入相应接口的代理。用户发起请求,先执行stub的逻辑访问缓存,如果没有在去provider获取。
  • 问题:
    • 缓存使用spring提供的封装redisTemplate,redisTemplate由spring管理
    /**
     *********************************************************
     ** @desc  : 用户管理本地存根,使用redis缓存用户信息
     ** @author  Pings
     ** @date    2019/3/29
     ** @version v1.0
     * *******************************************************
     */
    public class UserServiceStub implements UserService {
    
        private static final String USER_KEY_PREFIX = "user::";
    
        private static RedisTemplate<String, Object> redisTemplate;
    
        private final UserService userService;
    
        //**构造函数传入真正的远程代理对象
        public UserServiceStub(UserService userService) {
            this.userService = userService;
            redisTemplate = SpringContextUtil.getBean("redisTemplate");
        }
    
        @Override
        public User getById(int id) {
            return this.userService.getById(id);
        }
    
        @Override
        public User getByUserName(String userName) {
            String key = this.getKey(userName);
            User user = (User) redisTemplate.opsForValue().get(key);
            if(user == null) {
                user = this.userService.getByUserName(userName);
                redisTemplate.opsForValue().set(key, user);
            }
    
            return user;
        }
    
        @Override
        public IPage<User> findPage(IPage<User> page, User entity) {
            return this.userService.findPage(page, entity);
        }
    
        @Override
        public List<User> findAll() {
            return this.userService.findAll();
        }
    
        @Override
        public User save(User user) {
            //**删除缓存
            redisTemplate.delete(this.getKey(user.getUserName()));
    
            user = this.userService.save(user);
    
            return user;
        }
    
        @Override
        public int deleteById(int id) {
            //**删除缓存
            User user = this.userService.getById(id);
            redisTemplate.delete(this.getKey(user.getUserName()));
    
            return this.userService.deleteById(id);
        }
    
        @Override
        public int allotRole(int id, int[] roles, int currentUserId) {
            //**删除缓存
            User user = this.userService.getById(id);
            redisTemplate.delete(this.getKey(user.getUserName()));
    
            return this.userService.allotRole(id, roles, currentUserId);
        }
    
        //**获取用户在缓存中的key
        private String getKey(String userName) {
            return USER_KEY_PREFIX + userName;
        }
    
    }
    
    • stub由dubbo管理,无法使用spring注入,因此使用ApplcationContext.getBean(“redisTemplate”)
    • 编写SpringContextUtil继承ApplicationContextAware,然后在stub中使用SpringContextUtil.getBean(“redisTemplate”)获取redisTemplate
    • stub的初始化在SpringContextUtil之前,stub调用SpringContextUtil.getBean(“redisTemplate”)的时候,applicationContext为null
    • 把dubbo ApplicationConfig由配置文件改为JavaConfig,调整bean初始化顺序,在springContextUtil之后初始化dubbo
    @Bean
    @DependsOn("springContextUtil")
    public ApplicationConfig applicationConfig(){
        return new ApplicationConfig("pings-web-admin");
    
    • 启动报错:Duplicate application configs: <dubbo:application /> and <dubbo:application name=“pings-web-admin” id=“pings-web-admin” />
     @SuppressWarnings({"unchecked"})
    public void afterPropertiesSet() throws Exception {
        if (getConsumer() == null) {
            //**获取到两个ApplicationConfig的bean
            Map<String, ConsumerConfig> consumerConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ConsumerConfig.class, false, false);
            ......
    
    • 默认启用了一个没有参数的ApplicationConfig,bean名:com.alibaba.dubbo.config.ApplicationConfig#0,看上去像是spring xml配置的bean,没有配置名称。导致无法使用JavaConfig配置ApplicationConfig(未找到配置的位置)
    • 设置为非默认的ApplicationConfig,后面报错ApplicationConfig.application == null
    @Bean("applicationConfig")
    @DependsOn("springContextUtil")
    public ApplicationConfig applicationConfig(){
        ApplicationConfig config = new ApplicationConfig("pings-web-admin");
        //**设置为false,不会发生上述问题,但是后面报错ApplicationConfig.application == null
        config.setDefault(false);
        return config;
    }
    
    • 暂时没有解决办法,如果你有方法,麻烦告知
    • 替代方法,在yml中配置ApplicationConfig,在JavaConfig中配置RegistryConfig中配置
    @Bean
    @DependsOn("springContextUtil")
    public RegistryConfig registryConfig(){
        RegistryConfig config = new RegistryConfig();
        config.setId("client-admin");
        config.setAddress("zookeeper://192.168.1.111:2181");
    
        return config;
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值