1. What is Feign?
Feign is a declarative pseudo Http client that makes writing Http clients much easier. With Feign, you just create an interface and annotate it. It has pluggable annotations that use Feign annotations and JAX-RS annotations. Feign supports pluggable encoders and decoders. Feign integrates the Ribbon by default and is integrated with Eureka
2. What annotations do Feign have
The name of the | explain |
---|---|
@RequestLine | Methods define HttpMethod and urItemplate. expressions wrapped in {} in UriTemplate can be used on method parameters |
@Param | Automatic injection of @param method parameters defines template variables whose values can be resolved using template injection as names |
@Headers | Define header template variables on a class or method, using @param annotations to provide injection of parameter values. If the annotation is added to the interface class, all requests carry the corresponding Header information. If on a method, it will only be added to the corresponding method request |
@QueryMap | Method defines a key-value pair or POJO, and the parameter values are converted to a query string on the URL |
@HeaderMap | Method to define a HeaderMap, with UrlTemplate and HeaderTemplate types, using the @param annotation to provide parameter values |
@FeignClient | The annotation specifies the name of the microservice to be invoked, encapsulating the process of invoking user-API as the consumer invocation template. |
@EnableFeignClients | The scan declares that they are pretend client interfaces (@feignClient). Configure the component scan directive for use (@Configuration) class. |
@SpringQueryMap | Spring MVC is equivalent to OpenFeign’s {@QueryMap}. |
@ FeignClient,
The name of the | explain |
---|---|
Name, Value, and serviceId | Name is the alias of value, and value is also the alias of name. Name specifies the name of FeignClient. If the project uses the Ribbon, the name attribute is used as the name of the microservice for service discovery. ServiceId and value are used to specify the serviceId and are not used anymore. |
qualifier | This property is used to specify the value of the @Qualifier annotation, which is the Qualifier for the FeignClient and can be referenced using the modified value. |
url | The URL property is generally used for debuggers and allows us to manually specify the address of the @FeignClient call. |
decode404 | When an HTTP 404 error occurs, the decoder is called if the field bit is true, otherwise a FeignException is thrown |
configuration | Feign configuration class, you can customize Feign Encoder, Decoder, LogLevel, Contract. |
fallback | Define a fault tolerant processing class. When the remote interface fails to be called or times out, the fault tolerant logic of the corresponding interface will be called. The class specified by Fallback must implement the interface tagged with @FeignClient |
fallbackFactory | Factory class, used to generate examples of fallback classes. With this property we can implement fault-tolerant logic common to each interface, reducing repetitive code. |
path | The path property defines the unified prefix for the current FeignClient. |
primary | Whether to mark the pseudo proxy as the primary Bean. Default is true. |
@EnableFeignClients
The name of the | explain |
---|---|
value | Alias for the basePackages property, allowing for a more concise writing style. |
basePackage | Set up automatic scanning of base package paths with @FeignClient annotations. |
basePackageClasses | This property is a security alternative to the basePackages property. This property scans all classes decorated by @FeignClient under the package for each class specified; This requires consideration of creating a special tag class or interface in each package that has no purpose other than to be referenced by the attribute. |
defaultConfiguration | This property is custom configured for all Feign clients using @Configuration. |
clients | Sets the list of classes decorated by the @FeignClient annotation. If clients is not an empty array, FeignClient is loaded without automatic classpath scanning. |
2. Basic usage of feign
Basic examples of official website
interface GitHub {
@RequestLine("GET /repos/{owner}/{repo}/contributors")
List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo);
@RequestLine("POST /repos/{owner}/{repo}/issues")
void createIssue(Issue issue, @Param("owner") String owner, @Param("repo") String repo);
}
public class MyApp {
public static void main(String... args) {
GitHub github = Feign.builder().decoder(new GsonDecoder())
.target(GitHub.class, "https://api.github.com");
}
}
Copy the code
Basic example of OpenFeign
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
Copy the code
@SpringBootApplication
@EnableFeignClients
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@FeignClient("stores")
public interface StoreClient {
@RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json")
Store update(@PathVariable("storeId") Long storeId, Store store);
}
Copy the code
The HTTP CLIENT sample
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
Copy the code
# configuration
feign.httpclient.enabled = true
Copy the code
OkHttp sample
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
Copy the code
# configuration
feign.okhttp.enabled = true
Copy the code
Spring Cloud Feign configuration item
The name of the | explain |
---|---|
Logger.Level loggerLevel | Log Level. Default logger.level.none |
Integer connectTimeout | Connection timeout java.net.HttpURLConnection#getConnectTimeout (), if use Hystrix, the configuration is invalid connection timeout |
Integer readTimeout | Read timeout java.net.HttpURLConnection#getReadTimeout (), if use Hystrix, the configuration is invalid |
Class retryer | Retry interface implementation class, the default implementation remyer.never_retry |
Class errorDecoder | Error encoding, Default errordecoder.default () |
List<Class>requestInterceptors | Request interceptor |
Boolean decode404 | Whether to enable 404 encoding |
Class decoder | Decoder, which converts an HTTP response into an object, Spring Cloud Feign uses ResponseEntityDecoder |
Class encoder | An encoder that converts an object into an HTTP request body. Spring Cloud Feign uses SpringEncoder |
Class contract | Handles Feign interface annotations, and Spring Cloud Feign uses the Spring MVCContract implementation to handle Spring MVC annotations, which is why we can use Springmvc annotations. |
Configuration of the sample
feign:
client:
default-config: my-config
config:
my-config:
error-decoder: com.example.feign.MyErrorDecoder
logger-level: full
Copy the code
Configuration item source code parsing
-feignClientFactoryBean #configureFeign protected void configureFeign(FeignContext context, Feign.builder Builder) {// Config file, Begin to feign. Client FeignClientProperties properties = applicationContext. GetBean (FeignClientProperties. Class); if (properties ! = null) {if (properties. IsDefaultToProperties ()) {/ / using Java configuration configureUsingConfiguration config (the context, the builder); configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), builder); configureUsingProperties(properties.getConfig().get(this.name), builder); } else { configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), builder); configureUsingProperties(properties.getConfig().get(this.name), builder); configureUsingConfiguration(context, builder); } } else { configureUsingConfiguration(context, builder); // Feign default configuration}}Copy the code
Priority of configuration items
Type 1: The configuration file is not configured
Using Java config configuration, has a lower priority to the attitude of a single configuration 1, FeignClientsConfiguration Spring Cloud Feign global default configuration. 2. @enablefeignclients #defaultConfiguration customizes the global defaultConfiguration. FeignClient# Configuration Indicates the local configuration of a Feign interface.
Feign.client. default-to-properties=true(default true)
Java config and application properties (. Yml) configuration, a low priority to the attitude of a single configuration 1, FeignClientsConfiguration Spring Cloud Feign global default configuration. 2. @enablefeignclients #defaultConfiguration customizes the global defaultConfiguration. FeignClient# Configuration Indicates the local configuration of a Feign interface. Application. Properties (.yml) configure the global default configuration of the file, configure the feign.client. Default-config to specify the default value (defult), how to use, Properties (.yml) configuration file local configuration, specify @feignClient# name local configuration.
Feign.client. default-to-properties=false(default true)
Java config and application.properties(.yml) configuration, with priority from low to high. Configure the attribute feign.client.default-config to specify the default value (defult), how to use it, Properties (.yml) configuration file local configuration, specify @feignClient# name local configuration. 3, FeignClientsConfiguration Spring Cloud Feign global default configuration. 4. @enablefeignclients #defaultConfiguration specifies the global defaultConfiguration. FeignClient# Configuration Indicates the local configuration of a single Feign interface.
Copy the code
3. Feign source code brief analysis
Main process steps:
Register the FeignClient configuration class and FeignClient BeanDefinition
Instantiate FeignContext object FeignContext
Create Feign. Builder object
Generate load balancing proxy classes
Generate the default proxy class
Inject into the Spring container
Feign call flow chart
Register the FeignClient configuration class and FeignClient BeanDefinition
One, from the point of view to start the class began, the @ EnableFeignClients comments: @ Import (FeignClientsRegistrar. Class), we don't look at the above registerBeanDefinitions decomposition of two methods: Default configuration methods: 1) registered registerDefaultConfiguration: the above method to start class for reading the above @ EnableFeignClients feign related configuration class declaration in the annotation, the default name for the default, generally do not need to configure. Use the default FeignAutoConfiguration. There is a important method in the method: register configuration registerClientConfiguration, start the process there are two reading feign configuration class, the first will be packaged into FeignClientSpecification bean configuration class, injected into the container. This object is very important and contains the retry policy, timeout policy, logging and other configurations required by FeignClient. If a service is not set, it reads the default configuration. 2) Scanning FeignClient: RegisterFeignClients method mainly scanning classpath, for all the FeignClient generate corresponding BeanDefinition, here in the second place up with registerClientConfiguration register configuration method, The main thing here is to scan the directory under which each project's configuration class is loaded in the container. SpringCloud FeignClient actually makes use of Spring's proxy factory to generate proxy classes, so here all the FeignClient description BeanDefinition is set to FeignClientFactoryBean type. This class in turn inherits FactoryBean, which is obviously a proxy class. In spring, the FactoryBean is a FactoryBean that is used to create proxy beans, so it follows that feign wraps all feignClient beans as feignclientfactorybeans. This is the end of the scanning method. When does a proxy class trigger generation? When Spring refreshes the container and instantiates our business Service, if FeignClient is registered, Spring will instantiate the FeignClient and determine if it is a proxy bean. If it is a proxy bean, The getObject() method of FeignClientFactoryBean is called to generate the proxy bean.Copy the code
Instantiate FeignContext object FeignContext
Main process steps: A, instantiation FeignContex, instantiation Feign context object FeignContext 2, can see Feign configuration Settings to Feign container, And the elements in the collection Is what we mentioned above two call registerClientConfiguration method added, before and after the echo. However, when we introduced Sleuth, Obtain instances of feignContext is configured in the TraceFeignClientAutoConfiguration sleuthFeignContext: can see above creates a TraceFeignContext instance, Because the object inheritance FeignContext, at the same time, through the processor after FeignContextBeanPostProcessor postProcessAfterInitialization method returns TraceFeignContext, So in step 2 above by type to obtain: the applicationContext. GetBean (FeignContext. Class), eventually get TraceFeignContext.Copy the code
Create Feign. Builder object
Feign.builder Builder = get(context, feign.builder.class
1) use Feign alone, by loading FeignClientsConfiguration configuration to create Feign. Builder 2) introduced the hystrix, without introducing the sleuth, By loading FeignClientsConfiguration configuration to create HystrixFeign. Builder 3) at the same time introducing hystrix and sleuth, Loading TraceFeignClientAutoConfiguration configuration to create HystrixFeign. BuilderCopy the code
2. Set retry policy and log components
1) Feign. Builder specifies retry policy, log level, error code, etc. 2) FeignContext is cached. Each service corresponds to a FeignContext, and the service name is used as the key.Copy the code
3. Load the configuration in the following order: first load the configuration class for each service, then load the configuration class on the startup class annotation, and then load the default configuration class. What’s the good of that?
Spring's method of refreshing the container also caches all beans and does not instantiate them if they have been created. Therefore, each FeignClient configuration class is selected first, and the default configuration class is last.Copy the code
Generate load balancing proxy classes
One important judgment is whether the URL declared by FeignClient is empty to determine the specific proxy class to be generated
1) If the Ribbon proxy is empty, the Ribbon proxy will be loaded by default. @feignClient ("MyFeignClient") 2) If the url is not null, the default proxy class is generated, which is called hard coding. @FeignClient(value = "MyFeignClient",url = "http://localhost:8081")Copy the code
This makes it easy for developers to test, so they don’t have to worry about the registry, they just call HTTP, which is a nice development trick. Here the Client object is retrieved from the FeignContext context and there are three more cases:
1) No integration of ribbon and Sleuth: obtain the Default Client: Default instance. 2) Ribbon integrated, sleuth not integrated: get LoadBalanceFeignClient instance. 3) Integrate ribbon and Sleuth: TraceFeignClient instance will be acquiredCopy the code
Feign initializes the entire process of structuring the dynamic proxy
Create ReflectiveFeign from the inner class ParseHandlersByName. ReflectiveFeign The parse interface generates MethodMetadata 3, and ParseHandlersByName generates the RequestTemplate factory based on MethodMetadata Create SynchronousMethodHandler with ParseHandlersByName ReflectiveFeign create FeignInvocationHandler; Pass in the parameter SynchronousMethodHandler and bind DefaultMethodHandler to ReflectiveFeign to create a Proxy based on FeignInvocationHandlerCopy the code
Interface call process:
FeignInvocationHandler (); FeignInvocationHandler (); FeignInvocationHandler (); 3. Invoke the invoke method of the SynchronousMethodHandler based on the method argument passed in. Create a RequestTemplate from the Factory object requestTemplate.factory. The factory uses an Encode 4, SynchronousMethodHandler to traverse the list of RequestInterceptor properties as needed. 4. The SynchronousMethodHandler calls the apply method on its Target attribute. 5. The SynchronousMethodHandler calls its Client's execute method, passing in a Request object. 6. The Client converts the Request to an HTTP Request. When sent, the HTTP Response is converted to a Response object. 7. SynchronousMethodHandler calls a method called Decoder to decode the Response object and return. 8Copy the code
Generate the default proxy class
Now that you understand the logic of step 4, generating the default proxy class is easy to understand. The only difference is that the client implementation class is loadBalanceClient. Note: Regardless of the proxy class, the request is ultimately initiated by the execute method in feign.default, which uses HttpUrlConnection by Default.
Inject into the Spring container
Conclusion: through the spring refresh () method, trigger FeignClientFactoryBean. GetObject () method to obtain the proxy class, and then complete the injection process of the spring container. This implementation is similar to the Dubbo implementation, interested in their own research oh.
4, summarize
Feign extension point summary
The name of the | explain |
---|---|
Contract | The purpose of a Contract is to parse the interface methods and generate Rest definitions. Feign uses its own defined annotations by default, and also provides the JAXRSContract Javax.ws. Rs annotation interface implementation. SpringContract is the spring Cloud provides SpringMVC annotation implementation |
Client | Client.Default sends HTTP requests using the Java API’s HttpClientConnection; ApacheHttpClient uses Apache’s Http client to send requests. OkHttpClient uses the OKHttp client to send requests; RibbonClient Uses the Ribbon for client routing |
Decoder | Json decoder GsonDecoder, JacksonDecoder; XML decoder JAXBDecoder; Stream StreamDecoder |
Encoder | Default encoder, can only handle String and byte[]; Json encoder GsonEncoder, JacksonEncoder; XML encoder JAXBEncoder |
Target | HardCodedTarget Defaults to Target and does nothing. LoadBalancingTarget Uses the Ribbon for client routing |
Retryer | The Default policy is retrans-y. Default, which contains three parameters: interval, maximum interval, and retry times. The system will sleep the entered interval before the first retry. The sleep time for each retry is 1.5 times that of the previous one |
RequestInterceptor | Modifying the RequestTemplate, such as adding headers to all requests, can be done with an interceptor before the calling client sends a request |
InvocationHandler | Injected into Feign.Builder via InvocationHandlerFactory, Feign provides an extension to Hystrix for Hystrix access |
advantages
1. Good scalability, can have a lot of custom extension points, such as RxJava, Hystrix, etc. 2. 3. Springclound uses components by default. 4. API is simple to use, simplifying HTTP call APICopy the code
disadvantages
1. Many default implementations of components have some pitfalls to avoidCopy the code
This article is formatted using MDNICE