基于CSE的微服务工程实践-Native API先行
[Open API]( https://swagger.io/docs/specification/about/) 采用Swagger进行描述,能够灵活的支持RPC风格和REST风格的接口定义,并且考虑了跨平台接口定义要求。使用Swagger进行接口开发代码,需要熟悉这个规范,并理解和代码逻辑之间的约束关系,对于一些初步接触的设计人员来讲,这个过程会比较痛苦。 在不写Swagger的情况下,CSE推荐设计者可以先结合自己熟悉的开发语言,使用接口的方式定义RPC或者REST接口。本文以JAVA语言为例,描述设计者如何定义接口。
微服务架构下,所有微服务之间都通过暴露REST接口进行访问。从管理/设计者的视角,通常期望系统的边界清晰,规格可控,因此接口的开发是独立受控的。早期JAVA标准,比如JSR Validation API等,都通过API包的方式供实现者使用。借鉴这个思路,设计者在设计微服务的时候,也可以将微服务的接口在独立的jar包项目中提供,实现者应用这个jar包即可。
使用CSE设计公共的接口,建议设计者提供两个类:
· Service: 一个JAVA接口,这个接口可以由开发者实现。
· Endpoint: 接口的REST描述。
举个例子,Service定义了开发者如何实现这个服务,开发者可以看不到REST标签,不用思考和HTTP的映射关系。
public interface UserService { public SessionInfo login(String userName, String password); public SessionInfo getSession(String sessionId); public String ping(String message); }
Endpoint定义这个服务对外暴露的REST接口,可以采用Spring MVC或者JAX RS两种方式进行描述。Endpoint是一个具体实现类,但是其实现逻辑,全部代理给Service的实现。
@RestSchema(schemaId = "user") @RequestMapping(path = "/") @SwaggerDefinition(info = @Info(description = "用户认证、会话等管理", title = "用户管理接口", version = "v1"), basePath = "/") public class UserEndpoint { @Autowired private UserService userService; @PostMapping(path = "/v1/user/login", produces = MediaType.APPLICATION_JSON_VALUE) @ApiOperation(value = "登录") public SessionInfo login(@RequestParam(name = "userName") String userName, @RequestParam(name = "password") String password) { return userService.login(userName, password); } @GetMapping(path = "/v1/user/session", produces = MediaType.APPLICATION_JSON_VALUE) @ApiOperation(value = "查询会话") public SessionInfo getSession(@RequestParam(name = "sessionId") String sessionId) { return userService.getSession(sessionId); } @GetMapping(path = "/v1/user/ping", produces = MediaType.APPLICATION_JSON_VALUE) @ApiOperation(value = "系统测试接口") public String ping(@RequestParam(name = "message") String message) { return userService.ping(message); } }
[porter例子]( https://github.com/huaweicse/cse-java-chassis-samples/tree/master/porter ) 展现了这个设计思路。
接口定义的一些注意事项和讨论
上诉方式是在实践中探索的一种比较好的接口组织形式,当然可以有其他各种形式。比较常见的辩论形式有直接定义Endpoint接口,所有的标签写到Endpoint上,开发者只需要实现Endpoint即可。这种形式看起来更加的简洁,但是CSE没有提供这种开发方式的支持,即REST的标签必须在实现类上,不能出现在实现类的父类或者实现接口上。CSE考虑过是否提供这种开发模式的支持,后面放弃了。主要的原因是因为JAVA在语言机制上,并没有提供annotation的继承机制(class的annotation可以通过@Inherited继承,但是Method没有)。当然通过反射遍历也是可以获取到父类的annotation的,把技术建立在一个不可靠的技术基础上,会带来大量的问题。当然放弃这种模式还有其他原因,关于是否共享Interface供服务实现者实现和客户端开发引用存在大量的争论,感兴趣的开发者可以搜索网络,查询这方面的设计讨论。
注意事项
由于@RestSchema也是一个bean,在所有微服务的接口定义都在一个common jar包里面时,要避免一个微服务加载所有的bean。所以需要把不同服务的定义放到不同的package里面,通过ComponentScan控制加载范围或者创建不同的jar包,完全不引用。
- 点赞
- 收藏
- 关注作者
评论(0)