Several methods of remote invocation between microservices (RestTemplate, Eureka, Nacos, feign)

1.RestTemplate call

  1. First declare a bean in the caller's startup class:

    public class OrderApplication {
        public static void main(String[] args) {
            SpringApplication.run(OrderApplication.class, args);
        }
    
        //Implement remote call
        @Bean
        public RestTemplate restTemplate() {
            return new RestTemplate();
        }
    }
  2. Then, in the interface implementation to be imported, use resttemplate getForObject(url,XX.class)

    @Autowired
    private RestTemplate restTemplate;
    ​
    public Order queryOrderById(Long orderId) {
        // 1. Query order
        Order order = orderMapper.findById(orderId);
        // 4. Return
        //2. Remote call query user
        String url="http://127.0.0.1:8081/user/"+order.getUserId();
        User user=restTemplate.getForObject(url,User.class);
        order.setUser(user);
        return order;
    }

2: Eureka registry

  1. How does order service know the user service instance address?

    The process of obtaining address information is as follows:

    • After the user service instance is started, register its own information with Eureka server (Eureka server). This is called service registration

    • Eureka server saves the mapping relationship between service name and service instance address list

    • Order service pulls the instance address list according to the service name. This is called service discovery or service pull

  2. How does order service select a specific instance from multiple user service instances?

    • Order service selects an instance address from the instance list using the load balancing algorithm

    • Make a remote call to the instance address

  3. How does order service know whether a user service instance is still healthy and has been down?

    • User service will send a request to Eureka server at regular intervals (30 seconds by default) to report its status, which is called heartbeat

    • When no heartbeat is sent after a certain period of time, Eureka server will consider the microservice instance as faulty and remove it from the service list

    • When the order service pulls the service, the fault instance can be eliminated

Specific use:

  1. Introduce the starter dependency provided by SpringCloud for eureka:

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
  2. Write a startup class for eureka server service. Be sure to add an @ EnableEurekaServer annotation to enable the registration center function of eureka:

    package cn.itcast.eureka;
    ​
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
    ​
    @SpringBootApplication
    @EnableEurekaServer
    public class EurekaApplication {
        public static void main(String[] args) {
            SpringApplication.run(EurekaApplication.class, args);
        }
    }

  3. Write an application Properties file, as follows:

    server.port=8761
    spring.application.name=eureka-server
    eureka.client.service-url.defaultzone=http://127.0.0.1:8761/eureka

  4. In the pom file of the service provider user service, introduce the following Eureka client dependency:

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka- client</artifactId>
    </dependency>

  5. In the service provider user service, modify the application Properties file, add service name and eureka address:

    spring.application.name=userservice
    eureka.client.service-url.defaultZone=http://127.0.0.1:8761/eureka

  6. Similarly, for the caller of the service: order service, add the same dependency and modify the application Properties file

  7. For the service Caller: order service, add an annotation @ LoadBalanced in the startup class

    //Implement remote call
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

    When calling, replace the IP address and port in the previous url with the service name:

    public Order queryOrderById(Long orderId) {
        // 1. Query order
        Order order = orderMapper.findById(orderId);
        // 4. Return
        //2. Remote call query user
        String url="http://userservice/user/"+order.getUserId();
        User user=restTemplate.getForObject(url,User.class);
        order.setUser(user);
        return order;
    }

  8. The above process can register the services in the eureka registry, and the services can be called directly through the service name, but circular dependency is not recommended.

3: Nacos service registration and configuration center

Service registration:

  1. Decompress and install nacos locally, and start the nacos service in a stand-alone way in the browser http://127.0.01:8848/nacos Access to service information

  2. Introduce the dependency of SpringCloudAlibaba in < dependencymanagement > in the pom file of the cloud demo parent project:

    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-alibaba-dependencies</artifactId>
        <version>2.2.6.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>

    Then introduce the Nacos discovery dependency into the pom files in user service and order service:

    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>

  3. Configure the nacos address, cluster and load balancing rules of the service

    spring.cloud.nacos.server-addr=localhost:8848
    spring.cloud.nacos.discovery.cluster-name=HZ
    userservice.ribbon.NFLoadBalancerRuleClassName=com.alibaba.cloud.nacos.ribbon.NacosRule

  4. Multiple service producers can be replicated (configuration port, cluster name):

    -Dserver.port=8083 -Dspring.cloud.nacos.discovery.cluster-name=SH

The load balancing of nacos will give priority to the service instances in the same cluster to call, while in the same cluster, the service instances are called in a random way. This is the choice of changing the load balancing by selecting the weight of different instances under the same service.

Unified service configuration:

  1. On the nacos homepage, click [configuration management] - [configuration list] - click the + sign to add configuration, and then fill in the configuration information in the pop-up form:

    Data ID:  userservice-dev.properties
    Group: DEFAULT_GROUP
     Description: development environment configuration
     Configuration format: properties
     Configuration content: pattern.dateformat=yyyy-MM-dd HH:mm:ss

    Note: the core configuration of the project needs hot update before it is necessary to put it into nacos management. It is better to save some configurations that will not be changed locally.

  2. Microservices need to pull the configuration managed in nacos and connect with the local application YML configuration merging can complete the project startup.

    But if you haven't read application YML, how do you know the nacos address?

    Therefore, spring introduces a new configuration file: bootstrap Yaml file, which will be displayed in application YML was read before. The process is to read bootstrap first when the project is started The configuration information on yaml and nacos is integrated into the project and read the application Properties file, create the spring container and load the bean.

  3. First, in the user service service, the client dependency of Nacos config is introduced:

    <!--nacos Configuration management dependency-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>

  4. Then, add a bootstrap in the user service Properties file, as follows:

    spring.application.name=userservice
    spring.profiles.active=dev
    spring.cloud.nacos.server-addr=localhost:8848
    spring.cloud.nacos.config.file-extension=properties

    According to spring cloud. nacos. Get the Nacos address from server addr, and then

    ${spring.application.name}-${spring.profiles.active}.$ {spring. Cloud. Nacos. Config. File extension} is used as the file id to read the configuration.

  5. Add business logic to UserController in user service and read pattern Dateformat configuration:

    @Value("${pattern.dateformat}")
    private String dateformat;
        
    @GetMapping("now")
    public String now(){
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat));
    }

  6. Our ultimate goal is to modify the configuration in nacos so that the configuration can take effect without restart in the micro service, that is, configure hot update.

    Use the @ ConfigurationProperties annotation instead of the @ Value annotation.

    In the user service service, add a class and read the pattern Dateformat attribute:

    package cn.itcast.user.config;
    ​
    import lombok.Data;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.stereotype.Component;
    ​
    @Component
    @Data
    @ConfigurationProperties(prefix = "pattern")
    public class PatternProperties {
        private String dateformat;
    }

  7. Modify the business logic of UserController

    @Autowired
    private PatternProperties patternProperties;
    ​
    @GetMapping("now")
    public String now(){
        return LocalDateTime.now().format(DateTimeFormatter.
                                          ofPattern(patternProperties.getDateformat()));
    }

  8. Configure sharing: when creating a configuration, set the Data ID to the service name properties.

4: feign remote call

  1. There are some problems with using RestTemplate:

    • poor code readability and inconsistent programming experience

    • complex parameters and difficult to maintain URL s

  2. You can also create an independent module class and transfer it to a new module

  3. First, introduce feign dependency into the pom file of module service:

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>

  4. Create UserClient interface:

    @FeignClient(value ="userservice",configuration = DefaultFeignConfiguration.class)
    public interface UserClient {
        @GetMapping("/user/{id}")
        User findById(@PathVariable("id") Long id);
    }

  5. Import the dependency of feign API service in order service project:

    <dependency>
        <groupId>cn.itcast.demo</groupId>
        <artifactId>feign-api</artifactId>
        <version>1.0</version>
    </dependency>

  6. Modify the queryOrderById method in the OrderService class in order service, and use Feign client instead of RestTemplate:

    @Autowired
    private UserClient userClient;
    ​
    public Order queryOrderById(Long orderId) {
        // 1. Query order
        Order order = orderMapper.findById(orderId);
        // 4. Return
        //2. Remote call query user
        User user=userClient.findById(order.getUserId());
        order.setUser(user);
        return order;
    }

  7. Custom configuration, such as setting the type of log printer, and the log level is divided into four types:

    • NONE: no log information is recorded, which is the default value.

    • BASIC: only record the requested method, URL, response status code and execution time

    • HEADERS: on the basis of BASIC, additional header information of request and response is recorded

    • FULL: records the details of all requests and responses, including header information, request body and metadata.

    You can modify the log level based on Java code, first declare a class, and then declare a logger Level objects:

    public class DefaultFeignConfiguration  {
        @Bean
        public Logger.Level feignLogLevel(){
            return Logger.Level.BASIC; // The log level is BASIC
        }
    }

    If you want to take effect globally, put it in the @ EnableFeignClients annotation of the startup class: however, since the startup class and the configuration class are not in the same package, the annotation information needs to be modified

    @EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration .class) 
    =======
    @EnableFeignClients(basePackages = "com.yudh.feign.service")

    If it is partially effective, put it in the corresponding @ FeignClient annotation:

    @FeignClient(value ="userservice",configuration = DefaultFeignConfiguration.class)

Problems encountered during debugging

  1. Open multiple services for debugging in idea at the same time and connect to the same database of the same server. It is necessary to modify the maximum connection time of hikari. The error is as follows:

    - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@4fda9dd2 \
    (No operations allowed after connection closed.). Possibly consider using a shorter maxLifetime value.

    Amend as follows:

    spring.datasource.hikari.max-lifetime=20000
    The specific value should be less than the database wait_timeout field value

Tags: Java Microservices eureka

Posted by cparekh on Thu, 31 Mar 2022 10:21:54 +0300