Skip to content

Commit 3bfa9ed

Browse files
committed
Add GrpcClient soft bean registration and autowiring
1 parent 3236156 commit 3bfa9ed

File tree

2 files changed

+132
-1
lines changed

2 files changed

+132
-1
lines changed

grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/inject/GrpcClientBeanPostProcessor.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import static java.util.Objects.requireNonNull;
2121

22+
import java.beans.Introspector;
2223
import java.lang.reflect.Field;
2324
import java.lang.reflect.Member;
2425
import java.lang.reflect.Method;
@@ -32,7 +33,9 @@
3233
import org.springframework.beans.factory.BeanCreationException;
3334
import org.springframework.beans.factory.BeanDefinitionStoreException;
3435
import org.springframework.beans.factory.config.BeanPostProcessor;
36+
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
3537
import org.springframework.context.ApplicationContext;
38+
import org.springframework.context.ConfigurableApplicationContext;
3639
import org.springframework.core.annotation.AnnotationUtils;
3740
import org.springframework.util.ReflectionUtils;
3841

@@ -41,6 +44,7 @@
4144
import io.grpc.Channel;
4245
import io.grpc.ClientInterceptor;
4346
import io.grpc.stub.AbstractStub;
47+
import lombok.extern.slf4j.Slf4j;
4448
import net.devh.boot.grpc.client.channelfactory.GrpcChannelFactory;
4549
import net.devh.boot.grpc.client.nameresolver.NameResolverRegistration;
4650
import net.devh.boot.grpc.client.stubfactory.FallbackStubFactory;
@@ -53,6 +57,7 @@
5357
* @author Michael ([email protected])
5458
* @author Daniel Theuke ([email protected])
5559
*/
60+
@Slf4j
5661
public class GrpcClientBeanPostProcessor implements BeanPostProcessor {
5762

5863
private final ApplicationContext applicationContext;
@@ -130,6 +135,17 @@ protected <T> T processInjectionPoint(final Member injectionTarget, final Class<
130135
throw new IllegalStateException(
131136
"Injection value is null unexpectedly for " + name + " at " + injectionTarget);
132137
}
138+
139+
try {
140+
final ConfigurableListableBeanFactory beanFactory =
141+
((ConfigurableApplicationContext) applicationContext).getBeanFactory();
142+
beanFactory.registerSingleton(Introspector.decapitalize(injectionType.getSimpleName()), value);
143+
applicationContext.getAutowireCapableBeanFactory().autowireBean(value);
144+
} catch (Exception e) {
145+
log.warn("Could not register and autowire bean: {}",
146+
Introspector.decapitalize(injectionType.getSimpleName()));
147+
}
148+
133149
return value;
134150
}
135151

@@ -233,9 +249,9 @@ protected <T> T valueForMember(final String name, final Member injectionTarget,
233249
*
234250
* @param stubClass The stub class that needs to be created.
235251
* @param channel The gRPC channel associated with the created stub, passed as a parameter to the stub factory.
252+
* @return A newly created gRPC stub.
236253
* @throws BeanInstantiationException If the stub couldn't be created, either because the type isn't supported or
237254
* because of a failure in creation.
238-
* @return A newly created gRPC stub.
239255
*/
240256
private AbstractStub<?> createStub(final Class<? extends AbstractStub<?>> stubClass, final Channel channel) {
241257
final StubFactory factory = getStubFactories().stream()
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
* Copyright (c) 2016-2021 Michael Zhang <[email protected]>
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
5+
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
6+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
7+
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
8+
*
9+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
10+
* Software.
11+
*
12+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
13+
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
14+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
15+
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16+
*/
17+
18+
package net.devh.boot.grpc.test.inject;
19+
20+
import static org.junit.jupiter.api.Assertions.assertNotNull;
21+
22+
import javax.annotation.PostConstruct;
23+
24+
import org.junit.jupiter.api.Test;
25+
import org.springframework.beans.factory.annotation.Autowired;
26+
import org.springframework.beans.factory.annotation.Qualifier;
27+
import org.springframework.boot.test.context.SpringBootTest;
28+
import org.springframework.boot.test.context.TestConfiguration;
29+
import org.springframework.context.annotation.Bean;
30+
import org.springframework.test.annotation.DirtiesContext;
31+
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
32+
33+
import io.grpc.stub.AbstractStub;
34+
import lombok.extern.slf4j.Slf4j;
35+
import net.devh.boot.grpc.client.inject.GrpcClient;
36+
import net.devh.boot.grpc.client.stubfactory.StandardJavaGrpcStubFactory;
37+
import net.devh.boot.grpc.client.stubfactory.StubFactory;
38+
import net.devh.boot.grpc.test.config.BaseAutoConfiguration;
39+
import net.devh.boot.grpc.test.config.InProcessConfiguration;
40+
import net.devh.boot.grpc.test.config.ServiceConfiguration;
41+
import net.devh.boot.grpc.test.proto.TestServiceGrpc;
42+
43+
/**
44+
* Test case should cover auto wiring with field and method injection
45+
*/
46+
@Slf4j
47+
@SpringBootTest
48+
@SpringJUnitConfig(
49+
classes = {
50+
GrpcClientAutoWiringFieldAndMethodInjectionTest.TestConfig.class,
51+
GrpcClientAutoWiringFieldAndMethodInjectionTest.TestConfig2.class,
52+
InProcessConfiguration.class,
53+
ServiceConfiguration.class,
54+
BaseAutoConfiguration.class
55+
})
56+
@DirtiesContext
57+
public class GrpcClientAutoWiringFieldAndMethodInjectionTest {
58+
59+
@Autowired
60+
@Qualifier("testServiceBlockingStub")
61+
TestServiceGrpc.TestServiceBlockingStub testServiceBlockingStub; // created in TestConfig with @GrpcClient
62+
63+
@Autowired
64+
String aboutBlockingStubBean; // created in TestConfig2 with method injection
65+
66+
@Test
67+
void fieldInjectionAutoWiringTest() {
68+
assertNotNull(testServiceBlockingStub, "testServiceBlockingStub");
69+
}
70+
71+
@Test
72+
void methodInjectionAutoWiringTest() {
73+
assertNotNull(aboutBlockingStubBean, "aboutBlockingStubBean");
74+
}
75+
76+
@TestConfiguration
77+
public static class TestConfig {
78+
79+
@GrpcClient("test")
80+
TestServiceGrpc.TestServiceBlockingStub blockingStub;
81+
82+
@Bean
83+
StubFactory customStubFactory() {
84+
return new StandardJavaGrpcStubFactory() {
85+
86+
@Override
87+
public boolean isApplicable(final Class<? extends AbstractStub<?>> stubType) {
88+
return CustomStub.class.isAssignableFrom(stubType);
89+
}
90+
91+
@Override
92+
protected String getFactoryMethodName() {
93+
return "custom";
94+
}
95+
96+
};
97+
}
98+
99+
@PostConstruct
100+
public void init() {
101+
assertNotNull(this.blockingStub, "blockingStub");
102+
}
103+
}
104+
105+
@TestConfiguration
106+
public static class TestConfig2 {
107+
108+
@Bean
109+
public String aboutBlockingStubBean(
110+
@Autowired @Qualifier("testServiceBlockingStub") TestServiceGrpc.TestServiceBlockingStub blockingStub) {
111+
return blockingStub.toString();
112+
}
113+
}
114+
115+
}

0 commit comments

Comments
 (0)