多版本问题
官方说明多版本解决办法http://dubbo.apache.org/zh-cn/docs/user/demos/multi-versions.html
服务提供方当实现一个接口,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。
服务提供方在实现方法的注解里添加版本信息
import java.util.Arrays;
import java.util.List;
import org.apache.dubbo.config.annotation.Service;
import com.yhy.gmall.bean.UserAddress;
import com.yhy.gmall.service.UserService;
//版本1
@Service(version = "1")
public class UserServiceImpl implements UserService {
@Override
public List<UserAddress> getUserAddressList(String userId) {
System.out.println("UserServiceImpl.....old...");
UserAddress address1 = new UserAddress(1, "北京市昌平区宏福科技园综合楼3层", "1", "李老师", "010-56253825", "Y");
UserAddress address2 = new UserAddress(2, "深圳市宝安区西部硅谷大厦B座3层(深圳分校)", "1", "王老师", "010-56253825", "N");
return Arrays.asList(address1, address2);
}
}
import java.util.Arrays;
import java.util.List;
import org.apache.dubbo.config.annotation.Service;
import com.yhy.gmall.bean.UserAddress;
import com.yhy.gmall.service.UserService;
//版本2
@Service(version = "2")
public class UserServiceImpl2 implements UserService {
@Override
public List<UserAddress> getUserAddressList(String userId) {
System.out.println("UserServiceImpl.....new...");
UserAddress address1 = new UserAddress(1, "北京市昌平区宏福科技园综合楼3层", "1", "李老师", "010-56253825", "Y");
UserAddress address2 = new UserAddress(2, "深圳市宝安区西部硅谷大厦B座3层(深圳分校)", "1", "王老师", "010-56253825", "N");
return Arrays.asList(address1, address2);
}
}
消费者
在注解里添加版本信息,可以是提供方写的版本1或2;也可以是*,随机选取。
import java.util.List;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;
import com.yhy.gmall.bean.UserAddress;
import com.yhy.gmall.service.OrderService;
import com.yhy.gmall.service.UserService;
@Service
public class OrderServiceImpl implements OrderService {
//*代表随机选取一个版本
@Reference(version = "*")
UserService userService;
@Override
public List<UserAddress> initOrder(String userId) {
System.out.println("用户id:" + userId);
// 1、查询用户的收货地址
List<UserAddress> addressList = userService.getUserAddressList(userId);
for (UserAddress userAddress : addressList) {
System.out.println(userAddress.getUserAddress());
}
return addressList;
}
}
然后运行程序N次,发现打印的结果却是每次不一样
UserServiceImpl.....new...
UserServiceImpl.....old...
UserServiceImpl.....new...
UserServiceImpl.....old...
UserServiceImpl.....old...
UserServiceImpl.....new...
UserServiceImpl.....new...
UserServiceImpl.....new...
UserServiceImpl.....old...
UserServiceImpl.....new...
注意:如果加上超时时间,调用服务方的方法超出了指定时间(比如3秒)且消费者指定服务版本为*(随机),则会在重复调用两次(因为),因为出错,默认远程服务调用重试次数为2,所以总共,控制台打印三次。
本地存根
这篇介绍本地存根可以:https://zhuanlan.zhihu.com/p/98422736
官方文档:http://dubbo.apache.org/zh-cn/docs/user/demos/local-stub.html
在远程调用服务提供者的实现之前,如果需要做一些参数验证、缓存、判断、小功能等等,满足要求再调用服务提供者的远程服务,则我们可以通过编写一个本地存根来实现这种功能,就是类似aop环绕功能。
比如对上面的案例,调用UserService实现类之前做一些参数校验,就可以使用这个办法。
1.编写一个本地存根方法,这个方法一般都写在api公用模块里,boot-user-service-provider在依赖gmall-interface
public class UserServiceStub implements UserService {
private final UserService userService;
public UserServiceStub(UserService userService) {
this.userService = userService;
}
@Override
public List<UserAddress> getUserAddressList(String userId) {
System.out.println("本地存根。。。。。。。。。。。");
if (userId != null) {
return userService.getUserAddressList(userId);
}
return null;
}
}
2.在调用方法处,声明使用本地存根,注解方式就在@Reference里面添加stub属性,值为类全限定名。
@Service
public class OrderServiceImpl implements OrderService {
@Reference(timeout = 3000, version = "*", stub = "com.yhy.gmall.service.UserServiceStub")
UserService userService;
@Override
public List<UserAddress> initOrder(String userId) {
System.out.println("用户id:" + userId);
// 1、查询用户的收货地址
List<UserAddress> addressList = userService.getUserAddressList(userId);
for (UserAddress userAddress : addressList) {
System.out.println(userAddress.getUserAddress());
}
return addressList;
}
}
3.然后调用,查看结果,可以看到存根,先被调用,确认userId不为空才进入远程方法。
用户id:56133
本地存根。。。。。。。。。。。
北京市昌平区宏福科技园综合楼3层
深圳市宝安区西部硅谷大厦B座3层(深圳分校)
不能远程调用带泛型参数的方法
比如消费者(控制层调用服务层)使用了mybatis plus中的带泛型参数的方法
default T getOne(Wrapper<T> queryWrapper)
@Reference
private AdminService adminService;
@RequestMapping(value = "/info", method = RequestMethod.GET)
@ResponseBody
public Object getAdminInfo(HttpServletRequest request) {
Admin umsAdmin = adminService.getOne(new QueryWrapper<Admin>().eq("username", userName));
}
就无法 调用会报错
com.alibaba.dubbo.remoting.RemotingException: Fail to decode request due to: RpcInvocation [methodName=getOne, parameterTypes=[class com.baomidou.mybatisplus.core.conditions.Wrapper], arguments=null, attachments={path=com.yhy.gmall.ums.service.AdminService, input=1847, dubbo=2.6.2, version=0.0.0}]
但是调用不带泛型参数的就行
default T getById(Serializable id)
解决办法,封装起来调用,用的mp,所以封装mapper的调用
@Service
@Component
public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements AdminService {
@Override
public Admin getUserInfo(String userName) {
return adminMapper.selectOne(new QueryWrapper<Admin>().eq("username",userName));
}
}