1 使用方法
1.1 Provider
使用示例如下:
@RestSchema(schemaId = "springmvcHello")
@RequestMapping(path = "/springmvchello", produces = MediaType.APPLICATION_JSON)
public class SpringmvcHelloEndpoint implements Hello {
@Override
@RequestMapping(path = "/sayhi", method = RequestMethod.POST)
public String sayHi(@RequestParam(name = "name", defaultValue = "test") String name) {
return "Hello " + name;
}
@Override
@RequestMapping(path = "/sayhello", method = RequestMethod.POST)
public String sayHello(@RequestBody Person person) {
return "Hello person " + person.getName();
}
}
public interface Hello {
String sayHi(String name);
String sayHello(Person person);
}
microservice.yml配置如下:
servicecomb:
service:
application: springmvc-sample
name: springmvc
version: 0.0.1
registry:
# Default using local service center
address: http://localhost:30100
# address: https://cse.cn-south-1.myhuaweicloud.com
instance:
watch: false
config:
client:
# Default using local config center
# serverUri: https://cse.cn-south-1.myhuaweicloud.com
serverUri: http://localhost:30113
refreshMode: 1
1.2 Consumer
使用示例如下:
@Component("SpringmvcHelloClient")
public class SpringmvcHelloClient {
private static final Logger LOG = LoggerFactory.getLogger(SpringmvcHelloClient.class);
private static RestTemplate restTemplate = RestTemplateBuilder.create();
@RpcReference(microserviceName = "springmvc", schemaId = "springmvcHello")
private static Hello hello;
public void run() throws Exception {
Person person = new Person();
person.setName("ServiceComb/Java Chassis");
// RestTemplate Consumer or POJO Consumer. You can choose whatever you like
// 1 RestTemplate Consumer
String sayHiResult =
restTemplate.postForObject("cse://springmvc/springmvchello/sayhi?name={name}", null, String.class, "Java Chassis");
Assertion.assertEquals("Hello Java Chassis", sayHiResult);
String sayHiDefaultResult =
restTemplate.postForObject("cse://springmvc/springmvchello/sayhi", null, String.class);
Assertion.assertEquals("Hello test", sayHiDefaultResult);
String sayHelloResult = restTemplate.postForObject("cse://springmvc/springmvchello/sayhello", person, String.class);
Assertion.assertEquals("Hello person ServiceComb/Java Chassis", sayHelloResult);
System.out.println("RestTemplate Consumer or POJO Consumer. You can choose whatever you like.");
System.out.println("RestTemplate consumer sayhi services: " + sayHiResult);
System.out.println("RestTemplate consumer sayHiDefault services: " + sayHiDefaultResult);
System.out.println("RestTemplate consumer sayhello services: " + sayHelloResult);
// 2 POJO Consumer
String pojoSayHi = hello.sayHi("Java Chassis");
Assertion.assertEquals("Hello Java Chassis", pojoSayHi);
String pojoSayHello = hello.sayHello(person);
Assertion.assertEquals("Hello person ServiceComb/Java Chassis", pojoSayHello);
System.out.println("POJO consumer sayhi services: " + pojoSayHi);
System.out.println("POJO consumer sayhello services: " + pojoSayHello);
// 3 AsyncRestTemplate Consumer
// NOTICE: since 2.0.0, spring deprecated AsyncRestTemplate, user's can use CompletableFuture of RPC instead
CseAsyncRestTemplate cseAsyncRestTemplate = new CseAsyncRestTemplate();
ListenableFuture<ResponseEntity<String>> responseEntityListenableFuture = cseAsyncRestTemplate
.postForEntity("cse://springmvc/springmvchello/sayhi?name={name}", null, String.class, "Java Chassis");
ResponseEntity<String> responseEntity = responseEntityListenableFuture.get();
Assertion.assertEquals("Hello Java Chassis", responseEntity.getBody());
System.out.println("AsyncRestTemplate Consumer sayHi services: " + responseEntity.getBody());
HttpEntity<Person> entity = new HttpEntity<>(person);
ListenableFuture<ResponseEntity<String>> listenableFuture = cseAsyncRestTemplate
.exchange("cse://springmvc/springmvchello/sayhello", HttpMethod.POST, entity, String.class);
listenableFuture.addCallback(
new ListenableFutureCallback<ResponseEntity<String>>() {
@Override
public void onFailure(Throwable ex) {
LOG.error("AsyncResTemplate Consumer catched exception when sayHello, ", ex);
}
@Override
public void onSuccess(ResponseEntity<String> result) {
System.out.println("AsyncRestTemplate Consumer sayHello services: " + result.getBody());
}
});
}
}
cse展示了三种调用provider的方式,第二种方式,使用RPC的方式调用provider,本质都是发送http请求,consumer的实现逻辑不做进一步探讨。
2 初始化
Provider
provider中重要的注解是RestSchema,RestSchema注解扫描在RestProducers类中,实现如下:
@Component
public class RestProducers implements BeanPostProcessor {
private List<ProducerMeta> producerMetaList = new ArrayList<>();
// 1
@SuppressWarnings("unchecked")
private Class<? extends Annotation> restControllerCls = (Class<? extends Annotation>) ReflectUtils
.getClassByName("org.springframework.web.bind.annotation.RestController");
private boolean scanRestController = restControllerCls != null &&
DynamicPropertyFactory.getInstance().getBooleanProperty(RestConst.PROVIDER_SCAN_REST_CONTROLLER, true).get();
public List<ProducerMeta> getProducerMetaList() {
return producerMetaList;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
processProvider(beanName, bean);
return bean;
}
protected void processProvider(String beanName, Object bean) {
// aop后,新的实例的父类可能是原class,也可能只是个proxy,父类不是原class
// 所以,需要先取出原class,再取标注
Class<?> beanCls = BeanUtils.getImplClassFromBean(bean);
if (beanCls == null) {
return;
}
RestSchema restSchema = beanCls.getAnnotation(RestSchema.class);
if (restSchema != null) {
ProducerMeta producerMeta = new ProducerMeta(restSchema.schemaId(), bean);
producerMeta.setSchemaInterface(restSchema.schemaInterface());
producerMetaList.add(producerMeta);
return;
}
if (scanRestController && beanCls.getAnnotation(restControllerCls) != null) {
ProducerMeta producerMeta = new ProducerMeta(beanCls.getName(), bean);
producerMetaList.add(producerMeta);
}
}
}
在cse的实现中,首先扫描RestSchema注解,如果没有使用RestSchema注解,则扫描RestController注解,RestController注解生成的接口契约默认使用bean的名称作为schemaId,其实这就与Rpc的使用方式差别不大了。
3 调用方式
参见rpc调用方式。