# reactive-dubbo
**Repository Path**: cgb-middleware/reactive-dubbo
## Basic Information
- **Project Name**: reactive-dubbo
- **Description**: 基于Reactor开发的Dubbo扩展插件,使Dubbo能够发布响应式服务。Make your dubbo reactive!
- **Primary Language**: Java
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 1
- **Created**: 2021-01-15
- **Last Updated**: 2022-02-20
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README

--


Reactive support for [Dubbo](http://dubbo.apache.org) based on [REACTOR](https://projectreactor.io/)
## Getting started
### Install
```bash
# git clone https://github.com/cherrythefatbunny/reactive-dubbo.git
# cd reactive-dubbo
# mvn clean install
```
### Run redis and zookeeper
```bash
# cd demo/redis-and-zookeeper
# nohup mvn spring-boot:run &
```
### Run Demo Provider
```bash
# cd ../provider
# nohup mvn spring-boot:run &
```
### Run Demo Consumer
```bash
# cd ../consumer
# nohup mvn spring-boot:run &
```
## Getting involved
### Maven dependency
Both provider and consumer should add reactive-dubbo-starter dependency
```xml
com.github.cherrythefatbunny
reactive-dubbo-starter
1.0.2-SNAPSHOT
```
### Service definition
For provider side,you should define reactive services by specifying a reactive proxy factory(e.g.,reactivejavassist,reactivejdk. )
```java
@Service(proxy = "reactivejavassist")
public class ReactiveServiceImpl implements ReactiveService {
}
```
## Architecture
### Dubbo with Reactive Dubbo
To make dubbo reactive,Reactive Dubbo will replace invokers and proxies with the reactive ones by specifying a reactive proxy factory

### Reactive proxy
A reactive proxy (the reactiveInvokerInvocationHandler actually works) wraps a formal functional invocation into a reactive publisher
[ReactiveInvokerInvocationHandler.java](https://github.com/cherrythefatbunny/reactive-dubbo/blob/master/reactive-dubbo-extensions/src/main/java/com/github/cherrythefatbunny/reactive/dubbo/extensions/proxyfactory/ReactiveInvokerInvocationHandler.java):
```java
public class ReactiveInvokerInvocationHandler extends InvokerInvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//if the invocation returns a publisher,make a publisher wrapping the real invocation
Class returnType = method.getReturnType();
if(Publisher.class.isAssignableFrom(returnType)) {
RpcInvocation invocation = new RpcInvocation(method, args);
if(Mono.class.isAssignableFrom(returnType)) {
invocation.setAttachment("Publisher","mono");
return Mono.fromCallable(() -> {
try {
return invoker.invoke(invocation).recreate();
} catch (Throwable throwable) {
if(LOGGER.isWarnEnabled()) {
LOGGER.warn("mono call invoker error", throwable);
}
throw new Exception(throwable);
}
});
} else if(Flux.class.isAssignableFrom(returnType)) {
invocation.setAttachment("Publisher","flux");
return Flux.fromIterable(Mono.fromCallable(() -> {
try {
return (List)invoker.invoke(invocation).recreate();
} catch (Throwable throwable) {
if(LOGGER.isWarnEnabled()) {
LOGGER.warn("flux call invoker error", throwable);
}
throw new Exception(throwable);
}
}).block());
} else {
//TODO other publishers support
throw new IllegalArgumentException(
String.format("%s not supported now",method.getReturnType().getSimpleName()));
}
}
return super.invoke(proxy, method, args);
}
}
```
### Reactive invoker
A reactive invoker intercepts a formal remote request and convert its result into publisher's parameterized type(e.g. `Mono` -> `String`,`Flux` -> `List`)
[ReactiveProxyFactory.java](https://github.com/cherrythefatbunny/reactive-dubbo/blob/master/reactive-dubbo-extensions/src/main/java/com/github/cherrythefatbunny/reactive/dubbo/extensions/proxyfactory/ReactiveProxyFactory.java):
```java
public abstract class ReactiveProxyFactory extends AbstractProxyFactory {
@Override
public Invoker getInvoker(T proxy, Class type, URL url) throws RpcException {
Invoker invoker = delegating.getInvoker(proxy, type, url);
Invoker wrapper = (Invoker) Proxy.newProxyInstance(getClass().getClassLoader(),
new Class[]{Invoker.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object ret = method.invoke(invoker, args);
//extra process dealing with remote requests
if(method.getName().equals("invoke")&&
!LOCAL_PROTOCOL.equals(((RpcInvocation) args[0]).getInvoker().getUrl().getProtocol())) {
RpcResult rpcResult = (RpcResult) ret;
Object val = rpcResult.getValue();
//retrieve real returned value and create new RpcResult
if(val instanceof Mono) {
Mono mono = (Mono) val;
return new RpcResult(mono.block());
}
//retrieve real returned value,collect with an ArrayList and create new RpcResult
if(val instanceof Flux) {
Flux