This repository has been archived by the owner on Nov 15, 2023. It is now read-only.
forked from grpc-ecosystem/grpc-spring
/
GrpcClientAutoConfiguration.java
209 lines (190 loc) · 10 KB
/
GrpcClientAutoConfiguration.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
/*
* Copyright (c) 2016-2020 Michael Zhang <yidongnan@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package net.devh.boot.grpc.client.autoconfigure;
import java.util.Collections;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import io.grpc.CompressorRegistry;
import io.grpc.DecompressorRegistry;
import io.grpc.NameResolver;
import io.grpc.NameResolverProvider;
import io.grpc.NameResolverRegistry;
import net.devh.boot.grpc.client.channelfactory.GrpcChannelConfigurer;
import net.devh.boot.grpc.client.channelfactory.GrpcChannelFactory;
import net.devh.boot.grpc.client.channelfactory.InProcessChannelFactory;
import net.devh.boot.grpc.client.channelfactory.InProcessOrAlternativeChannelFactory;
import net.devh.boot.grpc.client.channelfactory.NettyChannelFactory;
import net.devh.boot.grpc.client.channelfactory.ShadedNettyChannelFactory;
import net.devh.boot.grpc.client.config.GrpcChannelsProperties;
import net.devh.boot.grpc.client.inject.GrpcClientBeanPostProcessor;
import net.devh.boot.grpc.client.interceptor.AnnotationGlobalClientInterceptorConfigurer;
import net.devh.boot.grpc.client.interceptor.GlobalClientInterceptorRegistry;
import net.devh.boot.grpc.client.nameresolver.ConfigMappedNameResolverFactory;
import net.devh.boot.grpc.client.nameresolver.NameResolverRegistration;
import net.devh.boot.grpc.common.autoconfigure.GrpcCommonCodecAutoConfiguration;
/**
* The auto configuration used by Spring-Boot that contains all beans to create and inject grpc clients into beans.
*
* @author Michael (yidongnan@gmail.com)
* @since 5/17/16
*/
@Configuration
@EnableConfigurationProperties
@AutoConfigureAfter(name = "org.springframework.cloud.client.CommonsClientAutoConfiguration",
value = GrpcCommonCodecAutoConfiguration.class)
public class GrpcClientAutoConfiguration {
@Bean
public static GrpcClientBeanPostProcessor grpcClientBeanPostProcessor(final ApplicationContext applicationContext) {
return new GrpcClientBeanPostProcessor(applicationContext);
}
@ConditionalOnMissingBean
@Bean
public GrpcChannelsProperties grpcChannelsProperties() {
return new GrpcChannelsProperties();
}
@ConditionalOnMissingBean
@Bean
public GlobalClientInterceptorRegistry globalClientInterceptorRegistry() {
return new GlobalClientInterceptorRegistry();
}
@Bean
public AnnotationGlobalClientInterceptorConfigurer annotationGlobalClientInterceptorConfigurer() {
return new AnnotationGlobalClientInterceptorConfigurer();
}
/**
* Creates a new NameResolverRegistration. This ensures that the NameResolverProvider's get unregistered when spring
* shuts down. This is mostly required for tests/when using the grpc's static default registry.
*
* @param nameResolverProviders The spring managed providers to manage.
* @return The newly created NameResolverRegistration bean.
*/
@ConditionalOnMissingBean
@Lazy
@Bean
public NameResolverRegistration grpcNameResolverRegistration(
@Autowired(required = false) List<NameResolverProvider> nameResolverProviders) {
return new NameResolverRegistration(nameResolverProviders);
}
/**
* Adds grpc's default registry to spring's application context.
*
* <p>
* <b>Note:</b> If multiple spring applications run in the same JVM, then you should consider creating separate
* registries.
* </p>
*
* @param registration The name resolver registration that contains all name resolver providers that should be
* registered.
* @return grpc's default name resolver bean.
*/
@ConditionalOnMissingBean
@Lazy // Not needed for InProcessChannelFactories
@Bean
public NameResolverRegistry grpcNameResolverRegistry(NameResolverRegistration registration) {
NameResolverRegistry registry = NameResolverRegistry.getDefaultRegistry();
registration.register(registry);
return registry;
}
/**
* Creates a new name resolver factory with the given channel properties. The properties are used to map the client
* name to the actual service addresses. If you want to add more name resolver schemes or modify existing ones, you
* can do that in the following ways:
*
* <ul>
* <li>If you only rely on the client properties or other static beans, then you can simply add an entry to java's
* service discovery for {@link io.grpc.NameResolverProvider}s.</li>
* <li>If you need access to other beans, then you have to manually register your NameResolverProvider in the
* {@link NameResolverRegistry}.</li>
* <li>If you want to change the behavior when no address is given, you have to overwrite this bean.</li>
* </ul>
*
* @param channelProperties The properties for the channels.
* @return The default config mapped name resolver factory.
*/
@ConditionalOnMissingBean(name = "grpcNameResolverFactory")
@Lazy // Not needed for InProcessChannelFactories
@Bean
@Primary
public NameResolver.Factory grpcNameResolverFactory(final GrpcChannelsProperties channelProperties,
NameResolverRegistry registry) {
return new ConfigMappedNameResolverFactory(channelProperties, registry);
}
@ConditionalOnBean(CompressorRegistry.class)
@Bean
public GrpcChannelConfigurer compressionChannelConfigurer(final CompressorRegistry registry) {
return (builder, name) -> builder.compressorRegistry(registry);
}
@ConditionalOnBean(DecompressorRegistry.class)
@Bean
public GrpcChannelConfigurer decompressionChannelConfigurer(final DecompressorRegistry registry) {
return (builder, name) -> builder.decompressorRegistry(registry);
}
@ConditionalOnMissingBean(GrpcChannelConfigurer.class)
@Bean
public List<GrpcChannelConfigurer> defaultChannelConfigurers() {
return Collections.emptyList();
}
// First try the shaded netty channel factory
@ConditionalOnMissingBean(GrpcChannelFactory.class)
@ConditionalOnClass(name = {"io.grpc.netty.shaded.io.netty.channel.Channel",
"io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder"})
@Bean
public GrpcChannelFactory shadedNettyGrpcChannelFactory(final GrpcChannelsProperties properties,
final NameResolver.Factory nameResolverFactory,
final GlobalClientInterceptorRegistry globalClientInterceptorRegistry,
final List<GrpcChannelConfigurer> channelConfigurers) {
final ShadedNettyChannelFactory channelFactory =
new ShadedNettyChannelFactory(properties, nameResolverFactory,
globalClientInterceptorRegistry, channelConfigurers);
final InProcessChannelFactory inProcessChannelFactory =
new InProcessChannelFactory(properties, globalClientInterceptorRegistry, channelConfigurers);
return new InProcessOrAlternativeChannelFactory(properties, inProcessChannelFactory, channelFactory);
}
// Then try the normal netty channel factory
@ConditionalOnMissingBean(GrpcChannelFactory.class)
@ConditionalOnClass(name = {"io.netty.channel.Channel", "io.grpc.netty.NettyChannelBuilder"})
@Bean
public GrpcChannelFactory nettyGrpcChannelFactory(final GrpcChannelsProperties properties,
final NameResolver.Factory nameResolverFactory,
final GlobalClientInterceptorRegistry globalClientInterceptorRegistry,
final List<GrpcChannelConfigurer> channelConfigurers) {
final NettyChannelFactory channelFactory =
new NettyChannelFactory(properties, nameResolverFactory,
globalClientInterceptorRegistry, channelConfigurers);
final InProcessChannelFactory inProcessChannelFactory =
new InProcessChannelFactory(properties, globalClientInterceptorRegistry, channelConfigurers);
return new InProcessOrAlternativeChannelFactory(properties, inProcessChannelFactory, channelFactory);
}
// Finally try the in process channel factory
@ConditionalOnMissingBean(GrpcChannelFactory.class)
@Bean
public GrpcChannelFactory inProcessGrpcChannelFactory(final GrpcChannelsProperties properties,
final GlobalClientInterceptorRegistry globalClientInterceptorRegistry,
final List<GrpcChannelConfigurer> channelConfigurers) {
return new InProcessChannelFactory(properties, globalClientInterceptorRegistry, channelConfigurers);
}
}