Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Note what are the specifications used by FeignClient

2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

In this article, the editor introduces in detail "what are the specifications used in annotating FeignClient", the content is detailed, the steps are clear, and the details are handled properly. I hope that this article "Annotation what are the specifications used in FeignClient" can help you solve your doubts.

Note the FeignClient usage specification is first of all to the commonly used attributes in FeignClient

ContextId: when there are multiple service invocation methods that do not want to be written in an interface, use the

Name: specify the name of the FeignClient. If the project uses the Ribbon,name attribute, it will be used as the name of the microservice for service discovery.

Url:url is generally used for debugging. You can specify the address of the @ FeignClient call manually.

Fallback: defines a fault-tolerant processing class. When the call to a remote interface fails or times out, the fault-tolerant logic of the corresponding interface will be called. The class specified by fallback must implement the @ FeignClient marked interface.

FallbackFactory: factory class, used to generate fallback class examples. Through this property, we can implement fault-tolerant logic common to each interface and reduce repetitive code.

Path: defines a unified prefix for the current FeignClient

Reasons for using FeignClient

Just let the interface of one micro-service be accessed by another service, one of the characteristics of micro-service is business isolation, it is necessary to achieve database isolation as far as possible, although not really isolated, but try to do isolation in the code.

For example, the system has a file-server, which is the public service of the system, and the interface implementation of downloading, uploading and obtaining content of attachments. The table corresponding to the operation is the system attachment table.

Now there is an attachment to the customer's information, and it is normal to make a table query between the customer and the attachment to get the attachment information, but it is illegal to do so in the micro-service. Now if you make the following reference

Interface methods defined in the controller class

/ / the interface method @ RequestMapping (value = "/ add", method = RequestMethod.GET) public Integer add (@ RequestParam Integer a, @ RequestParam Integer b) {ServiceInstance instance = client.getLocalServiceInstance (); Integer r = a + b; logger.info ("/ add, host:" + instance.getHost () + ", service_id:" + instance.getServiceId () + ", result:" + r); return r;}

Use @ FeignClient

FeignClient ("compute-service") public interface ComputeClient {@ RequestMapping (method = RequestMethod.GET, value = "/ add") Integer add (@ RequestParam (value = "a") Integer a, @ RequestParam (value = "b") Integer b);}

Then call the controller layer in another microservice

@ AutowiredComputeClient computeClient;@RequestMapping (value = "/ add", method = RequestMethod.GET) public Integer add () {return computeClient.add (10,20);}

It can only be said that the use is successful, but it is not standardized. This is an error specification that can be seen everywhere on the Internet. At first, I also misquoted it in the controll layer, but it was caught by the technical manager, but it was not compliant anyway.

The reason is simple: don't repeat the interface to the front end. What's the point if your controller invokes the original service, no matter which microservice it is, and the front end can be accessed directly? The interface is called for you to use to get useful information to process, and then return to the front end.

So it should be called at the server layer.

The use of @ FignClient annotations for specifications

Take the communication between the file service and the customer business module in the public service as an example.

Write the following in the api module of the file service

FeignClient (contextId = "fileService", value = ServicellaneConstants.FTLE_SERNVTCE,fallbackFactory=RenoteFileFallbackFactory.class) public interface RemoteFileservice {/ * * upload file * * aparam file file information * areturn result * / @ PostMapping (value = "/ upload", consumes = MediaType.WULTIPART_FORN_DATA_VALUE) public RcLong uplocad (CRequestParan ("module) String nodole, ORequestParan (" sunceId) String souneId, OlequestFart (value = "file") liltigartFile file)

At this time, in the customer business section, that is, the customer needs to make an one-to-many query of related information with attachments, and cannot be queried with tables, then call the RemoteFileservice above. At first, I wrote a FileController in the customer module, and then wrote the API, called in the API, and directly NO.

You should just call it in the business tier and use the annotation @ Autowired to get the data you need to process and process it.

Next, let's take a look at fallbackFactory, which is mainly for downgrading what should be returned if something goes wrong.

The code is for reference only. There may be other ways to write it.

/ Note FallbackFactory@componentpublic class RemoteFileFallbackFactory implements FallbackFactoryprivate static final Logger log = LoggerFactory.getLogger (RemoteFileFallbackFactory.class); 0verridepublic RemoteFileservice create (Throwable throwable) {/ / print error log log.error ("File friend call failed: {}", throwable.getHessage ()); return new RemoteFileserviceo {Overridepublic R upload (String module,String sourceId,MultipartFile file) {return R.fail ("upload failed:" + throwable.getMessage (o);} 0verridepublic byte [] getFileBytes (Long fileId) {return new byte [0] } @ 0verridepublic R getURL (Long [] ids) {return R.fail ("failed to get file URL:" + throwable.getHessage ());} @ 0verridepublic R getURL (List ids) {return R.fail ("failed to get file URL:" + throwable.getMessage ());}}

How do you want to use it? put it into practice.

Common problems with @ FeignClient annotations

Feign is a declarative Web service, and an interface to a Web service can be completed by defining an interface with corresponding annotations. After SpringCloud encapsulates Feign, it begins to support Spring MVC standard annotations, while combining Eureka and Ribbon on SpringCloud architecture, it can also support load balancing.

Since it is a Web service, it is necessary for both the server module and the client module to join the Feign dependency and docking api interface, which is the basic premise of Feign service. Therefore, the Feign interfaces introduced by both sides should be consistent, including service address, input parameter definition, return value, and so on.

Basic configuration

To enable the @ FeignClient interface, you first need to introduce Feign dependencies:

Org.springframework.cloud spring-cloud-starter-openfeign

You also need to introduce SpringCloud dependencies in the parent pom.xml so that it makes sense to use FeignClient.

Add the startup annotation @ EnableFeignClients to the startup class:

Import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.netflix.feign.EnableFeignClients; @ SpringBootApplication@EnableFeignClientspublic class FeignDemoApp {public static void main (String [] args) {SpringApplication.run (FeignDemoApp.class, args);}}

Then define the service interface provided by the Feign client. The sample code is as follows:

Import org.springframework.cloud.netflix.feign.FeignClient;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod; import com.demo.feign.model.request.FeignDemoDetailRequest;import com.demo.feign.model.response.FeignDemoDetailResponse;import com.demo.feign.model.response.FeignDemoListResponse FeignClient ("spring-boot-feign-demo") public interface FeignDemoClient {@ RequestMapping (value= "/ demo/list", method=RequestMethod.GET) public FeignDemoListResponse queryListByCode (@ PathVariable ("code") String code); @ RequestMapping (value= "/ demo/detail", method=RequestMethod.POST) public FeignDemoDetailResponse queryDetail (@ RequestBody FeignDemoDetailRequest request);}

The FeignDemoDetailRequest,FeignDemoDetailResponse and FeignDemoListResponse defined here are defined entity classes, which are not shown in detail.

common problem

Feign's maven relies on red, or @ EnableFeignClients is not recognized on the main startup class and always reports red, or feign API is injected into the controller to report red.

Possible reasons and solutions:

The maven package was not successfully imported, or the maven package download is incomplete. You can delete the dependent package from the repository and download and import it again.

If the version conflicts or the appropriate version cannot be obtained, you can specify the version number when the maven package is imported and try other available versions.

When the project Application starts, the FeignClient interface that is automatically injected with @ Autowired is told that the corresponding Bean cannot be found

* *

APPLICATION FAILED TO START

* *

Description:

Field feignDemoClient in com.xxx.xxx.service.impl.DemoServiceImpl required a bean of type 'com.xxx.xxx.feign.FeignDemoClient' that could not be found.

The injection point has the following annotations:

-@ org.springframework.beans.factory.annotation.Autowired (required=true)

Action:

Consider defining a bean of type 'com.xxx.xxx.feign.FeignDemoClient' in your configuration.

Disconnected from the target VM, address: '127.0.0.1 transport: 51645 socket'

Process finished with exit code 1

Possible reasons and solutions:

The service module does not introduce spring-cloud-starter-openfeign as a maven dependency in pom.xml, so just supplement this dependency to rebuild the project.

The project startup did not scan the package where the FeignClient interface is located. When the project starts through the startup class, it scans the class files in the same directory and under the same directory by default. Therefore, when Spring injects packages into third-party packages or other modules, you need to scan the packages that need to be injected. In this case, you only need to specify the package path to be scanned in the comments of the startup class, such as:

/ / Open the Feign client and specify the package @ EnableFeignClients ("com.xxx.xxx.feign") @ SpringBootApplication where the FeignClient API class is scanned.

Add Feign dependency correctly and start the class to scan all packet paths of api interface, but the injection interface still reports red

This is rare now, but it happened more frequently some time ago, mainly because the logic was optimized after the SpringBoot 2.0 release. Before SpringBoot 2. 0, if your Feign interface used GetMapping annotations, then injecting the interface would return red and could not be injected. Accordingly, you can inject it by changing it to RequestMapping or PostMapping.

Treatment plan:

1. Define the Feign interface in an appropriate annotation form. At present, there are basically the following feasible ways of definition:

@ FeignClient ("spring-boot-feign-demo") public interface FeignDemoClient {/ / specify Get method using RequestMapping. Input parameter @ RequestMapping (value= "/ demo/list", method=RequestMethod.GET) public FeignDemoListResponse queryListByCode (@ PathVariable ("code") String code); / / specify Post method using RequestMapping, and pass in entity @ RequestBody @ RequestMapping (value= "/ demo/detail", method=RequestMethod.POST) public FeignDemoDetailResponse queryDetail (@ RequestBody FeignDemoDetailRequest request) / / using PostMapping, passing in the entity using the annotation @ RequestBody @ PostMapping ("/ demo/seq") public FeignDemoSeqResponse querySeq (@ RequestBody FeignDemoSeqRequest request);}

Initiating a Get request via FeignClient to report a 405 error

By catching an exception at the server breakpoint, we can find that the direct cause of the 405 error is that the Feign interface defined as Get receives a call to the Post method. But most callers also use the Get method when calling, so what's the reason?

For the time being, the default Feign API is defined as follows:

@ FeignClient ("spring-boot-feign-demo") public interface FeignDemoClient {/ / the request received by the server is the Post method, not the Get method @ GetMapping (value= "/ demo/list") public Response queryList (Request request)

In fact, through the breakpoint to track the call path when the interface is called, you will find that FeignClient finally initiates a network connection through HttpURLConnection. In the process of initiating, Connection will determine whether the requested body is empty. If body is not empty, convert the Get method to the Post method. Because the data in the form of body can only be transmitted in the form of stream in the method RequestBody, while the data in the form of param according to the Http protocol can be transmitted and obtained directly on the URL.

The reason why this transformation occurs in FeignClient when a network request occurs is related to its initialization rules. During the project startup process, the @ FeignClient direct class is initialized with a dynamic proxy class and a request template is generated through a RequestTemplate.Factory factory class. The specific rules are as follows:

If the primitive type parameter is annotated with @ RequestParam, the parameter is put into RequestTemplate.Factory as key, and the array index is recorded through urlIndex. When parsing, the specific parameter values are obtained from the array through key and concatenated after url.

If the parameter does not have any annotations, or if there is a @ RequestBody annotation, the parameter index is maintained using bodyIndex during initialization and the specific type of the parameter is recorded through bodyType.

It is important to note that @ RequestParam can only be used to annotate a single primitive type parameter, not an entity class. When using entity classes as input and output parameters, it is recommended to use the Post method to make the request.

If you find it inconvenient to maintain the above correspondence in development, there is another modification method available. The basic principle is to use Apache's HTTP Client to replace the native Http Client of Feign. After replacement, the Get method can also use an entity class as the request parameter without worrying about the request being converted into the Post method. The specific modification methods are as follows:

Introduce http client dependency

Org.apache.httpcomponents httpclient

4.5.2 com.netflix.feign feign-httpclient 8.18.0

Enable the setting of httpClient by Feign

Feign.httpclient.enabled=true

After the configuration modification is completed, Apache's http client can be used internally. The definition of the Feign interface is the same, but because the Get method supports custom entity classes and is handled in a similar way to Post, the transmission of parameters requires us to specify their types extra to ensure that JSON serialization and deserialization work properly.

Here is a sample interface definition:

FeignClient ("spring-boot-feign-demo") public interface FeignDemoClient {@ PostMapping (value= "/ demo/detail", consumes = MediaType.APPLICATION_JSON_VALUE) public Response query (@ RequestBody FeignQueryRequest request, @ PathVariable ("page") Integer page, @ PathVariable ("page_size") Integer pageSize);}

JSON deserialization failed

Error while extracting response for type [com.xxx.xxx.feign] and content type [application/json]. Can not deserialize instance of java.util.ArrayList out of START_OBJECT token

The translation roughly means that the return value of the Feign API cannot be parsed in application/json format, that is, the definition of the return value of the caller is inconsistent with that of the server (different structure).

Treatment plan:

To ensure that the interface api introduced by both sides is exactly the same, you can ensure that the definition of the interface is consistent by packaging the module of the interface into a jar package and referencing the same jar by both parties.

After reading this, the article "what are the specifications used by FeignClient" has been introduced. If you want to master the knowledge of this article, you still need to practice and use it. If you want to know more about the article, you are welcome to follow the industry information channel.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report