-
Notifications
You must be signed in to change notification settings - Fork 216
add grpc client autowired #1309
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
214f911
911fefd
d6f59dc
9de8fad
e6b3b43
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package io.dapr.spring.boot.autoconfigure.client; | ||
|
||
import io.dapr.spring.invoke.grpc.client.DaprGrpcBeanPostProcessor; | ||
import org.springframework.boot.autoconfigure.AutoConfiguration; | ||
import org.springframework.boot.autoconfigure.AutoConfigureAfter; | ||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | ||
import org.springframework.context.ApplicationContext; | ||
import org.springframework.context.annotation.Bean; | ||
|
||
@AutoConfiguration | ||
@AutoConfigureAfter(DaprClientAutoConfiguration.class) | ||
public class DaprInvokeAutoConfiguration { | ||
|
||
@Bean | ||
@ConditionalOnProperty(name = "dapr.invoke.grpc.client.daprGrpcClient.enabled", havingValue = "true", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @seal90 what's the use case for this? When will people enable this property? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if instead of having this, we have something like @EnableDaprWorkflows, but looking at this example: https://www.baeldung.com/spring-boot-grpc, there is no need to disable this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This feature is enabled by default. For users who only use the HTTP protocol, there will be no impact as they do not use @ DaprGrpcClient. private <T extends AbstractStub<T>> T createStub(final Class<T> stubClass, final Channel channel) {
try {
// Search for public static *Grpc#new*Stub(Channel)
final Class<?> declaringClass = stubClass.getDeclaringClass();
if (declaringClass != null) {
for (final Method method : declaringClass.getMethods()) {
final String name = method.getName();
final int modifiers = method.getModifiers();
final Parameter[] parameters = method.getParameters();
if (name.startsWith("new") && name.endsWith("Stub")
&& Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers)
&& method.getReturnType().isAssignableFrom(stubClass)
&& parameters.length == 1
&& Channel.class.equals(parameters[0].getType())) {
return stubClass.cast(method.invoke(null, channel));
}
}
}
// Search for a public constructor *Stub(Channel)
final Constructor<T> constructor = stubClass.getConstructor(Channel.class);
return constructor.newInstance(channel);
} catch (final Exception e) {
throw new BeanInstantiationException(stubClass, "Failed to create gRPC client", e);
}
} |
||
matchIfMissing = true) | ||
static DaprGrpcBeanPostProcessor daprGrpcClientBeanPostProcessor( | ||
final ApplicationContext applicationContext) { | ||
return new DaprGrpcBeanPostProcessor(applicationContext); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
io.dapr.spring.boot.autoconfigure.client.DaprClientAutoConfiguration | ||
io.dapr.spring.boot.autoconfigure.client.DaprInvokeAutoConfiguration |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<parent> | ||
<groupId>io.dapr.spring</groupId> | ||
<artifactId>dapr-spring-parent</artifactId> | ||
<version>0.15.0-SNAPSHOT</version> | ||
</parent> | ||
|
||
<artifactId>dapr-spring-invoke</artifactId> | ||
<name>dapr-spring-invoke</name> | ||
<description>Dapr Spring Invoke</description> | ||
<packaging>jar</packaging> | ||
|
||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.sonatype.plugins</groupId> | ||
<artifactId>nexus-staging-maven-plugin</artifactId> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
</project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,233 @@ | ||
package io.dapr.spring.invoke.grpc.client; | ||
|
||
import com.google.common.collect.Lists; | ||
import io.dapr.client.DaprClient; | ||
import io.grpc.CallOptions; | ||
import io.grpc.Channel; | ||
import io.grpc.ClientInterceptor; | ||
import io.grpc.ClientInterceptors; | ||
import io.grpc.stub.AbstractAsyncStub; | ||
import io.grpc.stub.AbstractStub; | ||
import org.springframework.beans.BeanInstantiationException; | ||
import org.springframework.beans.BeansException; | ||
import org.springframework.beans.InvalidPropertyException; | ||
import org.springframework.beans.factory.BeanCreationException; | ||
import org.springframework.beans.factory.config.BeanPostProcessor; | ||
import org.springframework.context.ApplicationContext; | ||
import org.springframework.core.annotation.AnnotationAwareOrderComparator; | ||
import org.springframework.core.annotation.AnnotationUtils; | ||
import org.springframework.util.ReflectionUtils; | ||
|
||
import java.lang.reflect.Constructor; | ||
import java.lang.reflect.Field; | ||
import java.lang.reflect.Member; | ||
import java.lang.reflect.Method; | ||
import java.lang.reflect.Modifier; | ||
import java.lang.reflect.Parameter; | ||
import java.util.List; | ||
|
||
import static java.util.Objects.requireNonNull; | ||
|
||
/** | ||
* Handlers Dapr gRPC client in spring boot. | ||
* Searches for fields and methods in beans that are annotated with {@link DaprGrpcClient} and sets them. | ||
* | ||
*/ | ||
public class DaprGrpcBeanPostProcessor implements BeanPostProcessor { | ||
|
||
private final ApplicationContext applicationContext; | ||
|
||
private DaprClient daprClient; | ||
|
||
public DaprGrpcBeanPostProcessor(ApplicationContext applicationContext) { | ||
this.applicationContext = requireNonNull(applicationContext, "applicationContext"); | ||
} | ||
|
||
@Override | ||
public Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException { | ||
processDaprGprcClients(bean); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the checkstyle working? |
||
|
||
return bean; | ||
} | ||
|
||
/** | ||
* Process Dapr gRPC client in bean. | ||
* @param bean The bean to process. | ||
*/ | ||
private void processDaprGprcClients(final Object bean) { | ||
Class<?> clazz = bean.getClass(); | ||
do { | ||
processDaprGprcClientFields(clazz, bean); | ||
clazz = clazz.getSuperclass(); | ||
} while (clazz != null); | ||
} | ||
|
||
/** | ||
* Process DaprGrpcClient annotation in bean. | ||
* @param clazz The class to process. | ||
* @param bean The bean to process. | ||
*/ | ||
private void processDaprGprcClientFields(final Class<?> clazz, final Object bean) { | ||
for (final Field field : clazz.getDeclaredFields()) { | ||
final DaprGrpcClient annotation = AnnotationUtils.findAnnotation(field, DaprGrpcClient.class); | ||
if (annotation != null) { | ||
ReflectionUtils.makeAccessible(field); | ||
ReflectionUtils.setField(field, bean, processDaprGrpcClientPoint(field, field.getType(), annotation)); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Processes DaprGrpcClient announce and computes the appropriate value for the injection. | ||
* | ||
* @param <T> The type to be injected for the given injection point. | ||
* @param injectionTarget The target member for the injection. | ||
* @param injectionType The class that should injected type. | ||
* @param annotation The DaprGrpcClient annotation instance. | ||
* @return The value to be injected for the given injection point. | ||
*/ | ||
private <T> T processDaprGrpcClientPoint(final Member injectionTarget, final Class<T> injectionType, | ||
final DaprGrpcClient annotation) { | ||
final String name = annotation.value(); | ||
|
||
final List<ClientInterceptor> interceptors = interceptorsFromAnnotation(annotation); | ||
if (annotation.sortInterceptors()) { | ||
interceptors.sort(AnnotationAwareOrderComparator.INSTANCE); | ||
} | ||
|
||
return valueForMember(name, injectionTarget, injectionType, interceptors); | ||
} | ||
|
||
/** | ||
* Processes DaprGrpcClient announce with Channel or AbstractStub type. | ||
* | ||
* @param <T> The type of the instance to be injected. | ||
* @param <ST> The type of the AbstractStub implement class. | ||
* @param name The name of target service name. | ||
* @param injectionTarget The target member for the injection. | ||
* @param injectionType The class that should injected type. | ||
* @param interceptors The interceptors defined on DaprGrpcClient. | ||
* @return The value that matches the type of the given field. | ||
* @throws BeansException If the value of the field could not be created or the type of the field is unsupported. | ||
*/ | ||
protected <T, ST extends AbstractStub<ST>> T valueForMember(final String name, final Member injectionTarget, | ||
final Class<T> injectionType, | ||
final List<ClientInterceptor> interceptors) | ||
throws BeansException { | ||
if (Channel.class.equals(injectionType)) { | ||
Channel channel = getDaprClient().newGrpcStub(name, DaprGrpcBeanPostProcessor::newStub).getChannel(); | ||
channel = ClientInterceptors.interceptForward(channel, interceptors); | ||
return injectionType.cast(channel); | ||
} else if (AbstractStub.class.isAssignableFrom(injectionType)) { | ||
@SuppressWarnings("unchecked") | ||
ST stub = getDaprClient().newGrpcStub(name, (daprChannel -> | ||
createStub((Class<ST>)injectionType.asSubclass(AbstractStub.class), daprChannel))); | ||
stub = stub.withInterceptors(interceptors.toArray(new ClientInterceptor[0])); | ||
return injectionType.cast(stub); | ||
} else { | ||
if (injectionTarget != null) { | ||
throw new InvalidPropertyException(injectionTarget.getDeclaringClass(), injectionTarget.getName(), | ||
"Unsupported type " + injectionType.getName()); | ||
} else { | ||
throw new BeanInstantiationException(injectionType, "Unsupported grpc stub or channel type"); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Create a new stub by stubType and channel. | ||
* | ||
* @param stubClass The stub class that needs to be created. | ||
* @param channel The gRPC channel associated with the created stub, passed as a parameter to the stub factory. | ||
* @return A newly created gRPC stub. | ||
*/ | ||
private <T extends AbstractStub<T>> T createStub(final Class<T> stubClass, final Channel channel) { | ||
try { | ||
// Search for public static *Grpc#new*Stub(Channel) | ||
final Class<?> declaringClass = stubClass.getDeclaringClass(); | ||
if (declaringClass != null) { | ||
for (final Method method : declaringClass.getMethods()) { | ||
final String name = method.getName(); | ||
final int modifiers = method.getModifiers(); | ||
final Parameter[] parameters = method.getParameters(); | ||
if (name.startsWith("new") && name.endsWith("Stub") | ||
&& Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers) | ||
&& method.getReturnType().isAssignableFrom(stubClass) | ||
&& parameters.length == 1 | ||
&& Channel.class.equals(parameters[0].getType())) { | ||
return stubClass.cast(method.invoke(null, channel)); | ||
} | ||
} | ||
} | ||
|
||
// Search for a public constructor *Stub(Channel) | ||
final Constructor<T> constructor = stubClass.getConstructor(Channel.class); | ||
return constructor.newInstance(channel); | ||
} catch (final Exception e) { | ||
throw new BeanInstantiationException(stubClass, "Failed to create gRPC client", e); | ||
} | ||
} | ||
|
||
/** | ||
* Create a new stub by stubType and channel. | ||
* | ||
* @param channel The grpc channel. | ||
* @return The transparent stub instance. | ||
*/ | ||
private static DaprTransparentStub newStub(final Channel channel) { | ||
AbstractStub.StubFactory<DaprTransparentStub> factory = new AbstractStub.StubFactory<DaprTransparentStub>() { | ||
public DaprTransparentStub newStub(final Channel channel, final CallOptions callOptions) { | ||
return new DaprTransparentStub(channel, callOptions); | ||
} | ||
}; | ||
return DaprTransparentStub.newStub(factory, channel); | ||
} | ||
|
||
/** | ||
* A transparent stub that for DaprClient get channel. | ||
*/ | ||
private static class DaprTransparentStub extends AbstractAsyncStub<DaprTransparentStub> { | ||
private DaprTransparentStub(final Channel channel, final CallOptions callOptions) { | ||
super(channel, callOptions); | ||
} | ||
|
||
protected DaprTransparentStub build(final Channel channel, final CallOptions callOptions) { | ||
return new DaprTransparentStub(channel, callOptions); | ||
} | ||
} | ||
|
||
/** | ||
* Gets or creates the {@link ClientInterceptor}s that are referenced in the given annotation. | ||
* | ||
* @param annotation The annotation to get the interceptors for. | ||
* @return A list containing the interceptors for the given annotation. | ||
* @throws BeansException If the referenced interceptors weren't found or could not be created. | ||
*/ | ||
protected List<ClientInterceptor> interceptorsFromAnnotation(final DaprGrpcClient annotation) throws BeansException { | ||
final List<ClientInterceptor> list = Lists.newArrayList(); | ||
for (final Class<? extends ClientInterceptor> interceptorClass : annotation.interceptors()) { | ||
final ClientInterceptor clientInterceptor; | ||
if (this.applicationContext.getBeanNamesForType(interceptorClass).length > 0) { | ||
clientInterceptor = this.applicationContext.getBean(interceptorClass); | ||
} else { | ||
try { | ||
clientInterceptor = interceptorClass.getConstructor().newInstance(); | ||
} catch (final Exception e) { | ||
throw new BeanCreationException("Failed to create interceptor instance", e); | ||
} | ||
} | ||
list.add(clientInterceptor); | ||
} | ||
for (final String interceptorName : annotation.interceptorNames()) { | ||
list.add(this.applicationContext.getBean(interceptorName, ClientInterceptor.class)); | ||
} | ||
return list; | ||
} | ||
|
||
private DaprClient getDaprClient() { | ||
if (this.daprClient == null) { | ||
this.daprClient = this.applicationContext.getBean(DaprClient.class); | ||
} | ||
return this.daprClient; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package io.dapr.spring.invoke.grpc.client; | ||
|
||
import io.grpc.Channel; | ||
import io.grpc.ClientInterceptor; | ||
import io.grpc.stub.AbstractStub; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
|
||
import java.lang.annotation.Documented; | ||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Inherited; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
/** | ||
* An annotation for fields of type {@link Channel} or subclasses of {@link AbstractStub}/gRPC client services. | ||
* | ||
* <p> | ||
* <b>Note:</b> Fields that are annotated with this annotation should NOT be annotated with | ||
* {@link Autowired} (conflict). | ||
* </p> | ||
* | ||
*/ | ||
@Target({ElementType.FIELD}) | ||
@Retention(RetentionPolicy.RUNTIME) | ||
@Documented | ||
@Inherited | ||
public @interface DaprGrpcClient { | ||
|
||
/** | ||
* The name of the target service. The channel use DaprClient's grpc channel. | ||
* | ||
* <p> | ||
* <b>Example:</b> <code>@DaprGrpcClient("exampleService")</code> <-> | ||
* {@code headers.put(Metadata.Key.of("dapr-app-id", Metadata.ASCII_STRING_MARSHALLER), name); } | ||
* </p> | ||
* | ||
* @return The name of the target service. | ||
*/ | ||
String value(); | ||
|
||
/** | ||
* A list of {@link ClientInterceptor} classes that should be used with this client in addition to the globally | ||
* defined ones. If a bean of the given type exists, it will be used; otherwise a new instance of that class will be | ||
* created via no-args constructor. | ||
* | ||
* @return A list of ClientInterceptor classes that should be used. | ||
*/ | ||
Class<? extends ClientInterceptor>[] interceptors() default {}; | ||
|
||
/** | ||
* A list of {@link ClientInterceptor} beans that should be used with this client in addition to the globally | ||
* defined ones. | ||
* | ||
* @return A list of ClientInterceptor beans that should be used. | ||
*/ | ||
String[] interceptorNames() default {}; | ||
|
||
/** | ||
* Whether the custom ClientInterceptor defined by interceptors and interceptorNames should be sorted. | ||
* | ||
* <p> | ||
* Sorted by | ||
* {@code interceptors.sort(AnnotationAwareOrderComparator.INSTANCE)} | ||
* </p> | ||
* | ||
* | ||
* @return True, if the custom interceptors will be sorted. False otherwise. | ||
*/ | ||
boolean sortInterceptors() default false; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package io.dapr.springboot.examples.consumer.invoke.grpc; | ||
|
||
import io.dapr.springboot.examples.DaprExamplesProtos; | ||
import io.dapr.springboot.examples.HelloWorldGrpc; | ||
import io.dapr.spring.invoke.grpc.client.DaprGrpcClient; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RequestParam; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
@RestController | ||
public class HelloWorldController { | ||
|
||
@DaprGrpcClient("producer-app") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @seal90 ok.. I think I understand what is going on here.. Looking at this example: https://www.baeldung.com/spring-boot-grpc having it named @DaprGrpcClient makes sense. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The idea from https://github.com/grpc-ecosystem/grpc-spring. |
||
private HelloWorldGrpc.HelloWorldBlockingStub blockingStub; | ||
|
||
@RequestMapping("/hello") | ||
public String sayHello(@RequestParam("name") String name) { | ||
DaprExamplesProtos.HelloRequest request = DaprExamplesProtos.HelloRequest.newBuilder().setName(name).build(); | ||
DaprExamplesProtos.HelloReply reply = blockingStub.sayHello(request); | ||
return reply.getMessage(); | ||
Check warning on line 20 in spring-boot-examples/consumer-app/src/main/java/io/dapr/springboot/examples/consumer/invoke/grpc/HelloWorldController.java
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
<parent> | ||
<groupId>io.dapr</groupId> | ||
<artifactId>spring-boot-examples</artifactId> | ||
<version>0.15.0-SNAPSHOT</version> | ||
</parent> | ||
|
||
<artifactId>grpc-lib</artifactId> | ||
<name>grpc-lib</name> | ||
<description>protobuf files</description> | ||
|
||
<properties> | ||
<protobuf.output.directory>${project.build.directory}/generated-sources</protobuf.output.directory> | ||
<protobuf.input.directory>${project.basedir}/src/main/proto</protobuf.input.directory> | ||
</properties> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>io.grpc</groupId> | ||
<artifactId>grpc-protobuf</artifactId> | ||
<version>${grpc.version}</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>io.grpc</groupId> | ||
<artifactId>grpc-stub</artifactId> | ||
<version>${grpc.version}</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>io.grpc</groupId> | ||
<artifactId>grpc-api</artifactId> | ||
<version>${grpc.version}</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.google.protobuf</groupId> | ||
<artifactId>protobuf-java</artifactId> | ||
<version>${protobuf.version}</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.google.protobuf</groupId> | ||
<artifactId>protobuf-java-util</artifactId> | ||
<version>${protobuf.version}</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>javax.annotation</groupId> | ||
<artifactId>javax.annotation-api</artifactId> | ||
<version>1.3.2</version> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>com.github.os72</groupId> | ||
<artifactId>protoc-jar-maven-plugin</artifactId> | ||
<version>3.11.4</version> | ||
<executions> | ||
<execution> | ||
<phase>generate-sources</phase> | ||
<goals> | ||
<goal>run</goal> | ||
</goals> | ||
<configuration> | ||
<protocVersion>${protobuf.version}</protocVersion> | ||
<addProtoSources>inputs</addProtoSources> | ||
<includeMavenTypes>direct</includeMavenTypes> | ||
<includeStdTypes>true</includeStdTypes> | ||
<inputDirectories> | ||
<include>${protobuf.input.directory}</include> | ||
</inputDirectories> | ||
<outputTargets> | ||
<outputTarget> | ||
<type>java</type> | ||
<outputDirectory>${protobuf.output.directory}</outputDirectory> | ||
</outputTarget> | ||
<outputTarget> | ||
<type>grpc-java</type> | ||
<outputDirectory>${protobuf.output.directory}</outputDirectory> | ||
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}</pluginArtifact> | ||
</outputTarget> | ||
</outputTargets> | ||
</configuration> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-site-plugin</artifactId> | ||
<configuration> | ||
<skip>true</skip> | ||
</configuration> | ||
</plugin> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-checkstyle-plugin</artifactId> | ||
<configuration> | ||
<!-- Skip checkstyle for auto-generated code --> | ||
<skip>true</skip> | ||
</configuration> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
|
||
</project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
syntax = "proto3"; | ||
|
||
package daprexamples; | ||
|
||
option java_outer_classname = "DaprExamplesProtos"; | ||
option java_package = "io.dapr.springboot.examples"; | ||
|
||
// User Code definitions | ||
service HelloWorld { | ||
// Sends a greeting | ||
rpc SayHello (HelloRequest) returns (HelloReply) {} | ||
|
||
} | ||
|
||
// The request message containing the user's name. | ||
message HelloRequest { | ||
string name = 1; | ||
} | ||
|
||
// The response message containing the greetings | ||
message HelloReply { | ||
string message = 1; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package io.dapr.springboot.examples.producer.invoke.grpc; | ||
|
||
import io.dapr.springboot.examples.HelloWorldGrpc; | ||
import net.devh.boot.grpc.server.service.GrpcService; | ||
|
||
@GrpcService | ||
public class HelloWorldProducer extends HelloWorldGrpc.HelloWorldImplBase { | ||
|
||
@Override | ||
public void sayHello(io.dapr.springboot.examples.DaprExamplesProtos.HelloRequest request, | ||
io.grpc.stub.StreamObserver<io.dapr.springboot.examples.DaprExamplesProtos.HelloReply> responseObserver) { | ||
io.dapr.springboot.examples.DaprExamplesProtos.HelloReply reply = io.dapr.springboot.examples.DaprExamplesProtos.HelloReply.newBuilder() | ||
.setMessage("Hello " + request.getName()) | ||
.build(); | ||
responseObserver.onNext(reply); | ||
responseObserver.onCompleted(); | ||
} | ||
Check warning on line 17 in spring-boot-examples/producer-app/src/main/java/io/dapr/springboot/examples/producer/invoke/grpc/HelloWorldProducer.java
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@seal90 why do we need a new module?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my head a new module makes sense if we want to isolate the gRPC dependencies because we think they might clash with other dependencies on the client application.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The abilities possessed by DAPR:service invocation, publish/subscribe, workflow, statemanagement, bindings...
dapr-spring model: data(state), messageing, workflows
example page: https://github.com/dapr/java-sdk/tree/master/examples/src/main/java/io/dapr/examples
I think we split the module by abilitie, so i create a new module.