一、现有的架构
本项目采取ddd架构,在复杂ddd领域驱动设计的基础上简化保留精髓:
二、微服务rpc时,存在的代码耦合问题
当subject微服务中某个方法需要调用auth微服务时,需要在subject中声明auth的feignClient,然而在auth的controller入口层,采用的为dto对象,此时需要将各种dto也在subject微服务中引入,增加了代码耦合度;
为了解决这一问题,可以通过api对外接口层,将自身的feign接口提供给外部,当subject想要进行rpc时,只需在infra基础设施层中引入auth-api即可。而auth微服务的api层和controller都需要dto对象,此时只需把dto对象留在api层,contoller的pom文件引入api层即可进行解耦。common层中的result和resultCodeEnum同理,他们只在controller中被引用,抽取到api层无影响。
三、实践
3.1 在jc-club-auth-api层中引入OpenFeign依赖
<!--OpenFeign依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>3.0.6</version>
</dependency>
<!--负载均衡器-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
<version>3.0.6</version>
</dependency>
3.2 在jc-club-auth-api层 编写feignclient、抽取dto和result对象
@FeignClient(name = "jc-club-auth") //微服务名称
public interface UserFeignService {
/**
* 获取用户信息
*/
@RequestMapping("/user/getUserInfo")
Result<AuthUserDTO> getUserInfo(@RequestBody AuthUserDTO authUserDTO);
}
3.3 在subject-infra中引入auth-api
<!--auth微服务feign对外接口层-->
<dependency>
<groupId>com.ssm</groupId>
<artifactId>jc-club-auth-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
3.4 在subject微服务进行防腐隔离
rpc查询用户信息时返回整个AuthUserDto,而在subject微服务中,只需获取username,nickname即可, 这里单独创建UserInfo对象,作为UserFeign.getUserInfo的返回类型,进行防腐隔离。
@Data
public class UserInfo {
private String userName;
private String nickName;
}
@Component
public class UserRpc {
@Resource
private UserFeignService userFeignService;
public UserInfo getUserInfo(String userName) {
AuthUserDTO authUserDTO = new AuthUserDTO();
authUserDTO.setUserName(userName);
Result<AuthUserDTO> result = userFeignService.getUserInfo(authUserDTO);
UserInfo userInfo = new UserInfo();
if(!result.getSuccess()) {
return userInfo;
}
AuthUserDTO data = result.getData();
userInfo.setUserName(data.getUserName());
userInfo.setNickName(data.getNickName());
return userInfo;
}
}
3.5 启动类开启feign注解
@SpringBootApplication
@ComponentScan("com.ssm") //包扫描,在别的模块下可能也有com.ssm的包,需要
@MapperScan("com.ssm.**.mapper") //扫描mapper接口
@EnableFeignClients(clients = {UserFeignService.class}) //开启feign,指定需要加载的Client接口字节码,不然扫描不到feign容器
public class SubejctApplication {
public static void main(String[] args) {
SpringApplication.run(SubejctApplication.class, args);
}
}
3.6 测试
@RestController
@RequestMapping("/subject/category")
@Log4j2
public class TestUserFeignController {
@Resource
private UserRpc userRpc;
@GetMapping("/test")
public void test() {
UserInfo userInfo = userRpc.getUserInfo("oj6nl68fpFPRVxdHfzZZX-4GjK7U");
System.out.println(userInfo);
}
}