Backend——"coding+webhook realizes automatic refresh of springcloud configuration center

 

  • Foreword:

 problem:

1: Q: What is coding?

1: Answer: Like Code Cloud and github, it is a code hosting platform.

2: Q: What is a webhook?

2: Answer: A webhook is a way to request an interface or change the behavior of the page through a callback. When the user performs an operation on the website, the source website can initiate an HTTP request to the URL configured by the webhook. After configuration, users can trigger events on one site and then call the behavior of another site. It can be any operation.

3: Q: What is the spring cloud configuration center (Spring Cloud Config)?

3: Answer: In a stand-alone project, we generally put configuration files such as application.yml and application.properties in the root directory of the project or under the resources folder. But in a distributed system, when there are multiple microservices , we generally put the configuration file on a remote site such as github, code cloud or coding, and the program reads the configuration file from the remote instead of locally. . These files configured at the remote end can be understood as the configuration center.

4: Q: What is the automatic refresh of the configuration center?

4: Answer: In a stand-alone project, our configuration file is placed in the project directory. After changing a configuration, you only need to restart the project to read it again. But in a distributed system, when there are multiple microservices , our configuration files are placed on remote sites such as github. After changing the configuration, it is impossible to restart the microservices to read them one by one, so we need to refresh the configuration automatically. . The configuration center of springcloud provides a refresh interface to realize the function of refreshing the configuration without restarting the service. But this is not about automatic , so we combine the function of webhook, configure the interface address of the refresh interface in the webhook, and then modify the file remotely, trigger the callback method of the webhook to request the interface to refresh the configuration, and then it can refresh automatically. The configuration of the project. 


  • Implementation steps

  1. There are at least 3 microservice programs or microservice modules in the local sringcloud project. They are: service registration center (eureka-server), configuration center (config-server), business module (the custom name of my business module a is: policy-receive). There is nothing to say about the configuration of the service registry (eureka-server). The configuration of the configuration center and business modules is a bit more complicated, which will be discussed later

  2. Create a configuration file on coding or github (take coding as an example later). The configuration file must be prefixed by the custom name of the module, and suffixed by the development, testing, and production identification. The remote configuration file is as follows

  3. config-server (Configuration Center Configuration)

    3.1: Download and install start rabbitMQ, enter localhost:15762 in the browser after successful startup, and the following interface appears after logging in with guest

    3.2: Add dependencies in the configuration center module (config-server), focusing on the two jar packages spring-cloud-starter-bus-amqp and spring-boot-starter-actuator, and the rest are some regular jar packages of springcloud.

    3.3: Modify the configuration file application.yml in the configuration center module (config-server), and add the following four configurations, namely git connection configuration, rabbit configuration, microservice registration configuration, and refresh configuration.

    server:
      port: 8762
    spring:
      application:
        name: config-server
      cloud:
        config:
          server:
            git:
              uri: https://xxx/xxx.git   #git仓库地址
              username: xxxx             #git仓库用户名,如果是开源仓库可以不配
              password: xxxx             #git仓库密码,如果是开源仓库可以不配
    rabbitmq:
      host: localhost
      port: 5672                         #rabbitmq的页面端口是15762,业务端口是5762,这里配5762
      username: guest                    #游客默认账号
      password: guest                    #游客默认密码
    eureka:
      client:
        registerWithEureka: true         #是否将自己注册进去eureka,false为不注册,true注册
        fetchRegistry: true              #是否从eureka抓取注册信息,单点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
        serviceUrl:                      #服务注册中心地址,服务注册模块的端口号是8761,所以此处地址为http://localhost:8761/eureka/
          defaultZone:  http://localhost:8761/eureka/
    management:
      endpoints:
        web:
          exposure:
            include: bus-refresh          # 指定刷新地址
    

    3.4: Configuration center startup file, add two annotations @EnableDiscoveryClient and @EnableConfigServer. The first annotation means to be registered as a microservice client, and the second annotation means that the current program is used as the configuration center. So far, springcloud-config has been configured.

     

  4. Configuration of business microservices

    4.1: As you can see in the above figure, I have two local business-related microservices. I take one of them as an example (the name of the microservice is: policy-receive), and the following code and project structure are provided. It is worth noting that: 1 : When we are creating a springboot microservice project, the name of the configuration file is generally application.yml or application.properties. But because we want to realize the automatic refresh of the configuration file, we have to rename application.yml (or application.properties) to bootstrap.yml (or bootstrap.properties). Because the loading order of bootstrap.yml is before application.yml, only the application file on coding is obtained from bootstrap.yml, and then the program reads the remote application file. 2 : The naming problem of the remote configuration file. The configuration file naming on coding needs to follow the most basic rule of client microservice name + environment identification. As shown in the remote configuration file diagram in the second step above, the environment identification is shown in the following diagram. 3 : If the remote configuration file has the same attributes as the local bootstrap.yml file, then the remote configuration will replace the local configuration.

    spring:
      application:
        name: policy-receive                       #微服务的名称
      cloud:
        config:
          discovery:
            enabled: true                          #允许被注册中心发现
            service-id: config-server              #注册中心的名称
          profile: dev                             #配置中心文件的环境标识,dev代表开发环境,uat代表测试环境,pro代表生产环境。
          uri: http://localhost:8762               #配置中心的地址
      main:
        allow-bean-definition-overriding: true     #当遇到同样名字的时候,是否允许覆盖注册
      rabbitmq:
        host: localhost                            #rabbitmq的配置,没什么好讲的
        port: 5672
        username: guest
        password: guest
    eureka:
      client:
        fetch-registry: true                        #要不要去注册中心获取其他服务的地址
        register-with-eureka: true                  #要不要在注册中心注册
        service-url:
          defaultZone: http://localhost:8761/eureka/ #注册中心的地址
    

    4.2: The main dependency of the pom file (please ignore other business-related dependencies)

    4.3: Add annotations to the startup class, mainly the two annotations @EnableEurekaClient and @EnableDiscoveryClient. The basic local configuration has been completed.

  5. The webhook configuration of the code repository on coding

5.1: Go to the code warehouse to find the project settings, as follows

It should be noted here that the url of this webhook is the URL + path of the configuration center (config-server), and the form of ip address: port number + path cannot be used. So I used peanut shells to map my intranet ip to the port number 8762 of the configuration center (config-server). As for why the url path is bus-refresh, it is because we mentioned in 3.3 of the third major step above that the refresh address specified in the configuration file is bus-refresh. Select the code repository where the configuration file is located in the drop-down box in the code repository on this page. So far, the webhook configuration on the coding side has been completed.

5.2: Next, we will conduct a ping test of webhook. First, start the three microservices of the local registry, configuration center, and business program in turn . After starting up, we can open the registry to see the configuration center and business programs, as well as being discovered and registered by the registry

Then we return to the coding webhook page and see that there is already a webhook configuration we just added in the list, click ping to test

When the sent test pops up on the page, we click on the details and view the sending record to see the request header and request body of the request we just sent.

At the same time, we can see that our configuration center has received a request. The content of the request is as follows. It means that our webhook configuration is fine.

5.3: Next, perform actual business tests.

We create a new controller in the business module and annotate the path of the controller through RequestMapping. Note that the annotations are automatically refreshed through RefreshScope.

Define a String variable in the controller, and the value of the variable is injected through the Value annotation, which is the value of the bonecp.driverClass attribute in the remote configuration file.

Write another method to return the value of this String variable.

Then we open postman and request this interface of the business module, and we can see that the returned value is the value of the configuration file of the coding warehouse.

Then we modify this attribute of the coding warehouse and click Submit. After submitting the request directly in postman, you can see that the return value changes accordingly.

So far we have implemented the function of automatic configuration of coding+webhook microservices.

5.4: If the webhook request error or the local configuration center reports an error

Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token
 at [Source: (PushbackInputStream); line: 1, column: 62] (through reference chain: java.util.LinkedHashMap["hook"])]

If the above error occurs, it is because when the webhook requests the configuration center, the request body contains parameters that cannot be deserialized by json. We need to manually add filtering of request parameters from webhook in the configuration center.

code show as below:

import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;


@Component
public class UrlFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String url = httpServletRequest.getRequestURI();
        //只过滤/actuator/bus-refresh请求
        if (!url.endsWith("/bus-refresh")) {
            chain.doFilter(request, response);
            return;
        }
        //获取原始的body
        String body = readAsChars(httpServletRequest);
        System.out.println("original body:   " + body);
        //使用HttpServletRequest包装原始请求达到修改post请求中body内容的目的
        CustometRequestWrapper requestWrapper = new CustometRequestWrapper(httpServletRequest);
        chain.doFilter(requestWrapper, response);

    }

    @Override
    public void destroy() {

    }

    private class CustometRequestWrapper extends HttpServletRequestWrapper {
        public CustometRequestWrapper(HttpServletRequest request) {
            super(request);
        }

        @Override
        public ServletInputStream getInputStream() throws IOException {
            byte[] bytes = new byte[0];
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
            return new ServletInputStream() {
                @Override
                public boolean isFinished() {
                    return byteArrayInputStream.read() == -1 ? true : false;
                }

                @Override
                public boolean isReady() {
                    return false;
                }

                @Override
                public void setReadListener(ReadListener readListener) {

                }

                @Override
                public int read() throws IOException {
                    return byteArrayInputStream.read();
                }
            };
        }
    }

    public static String readAsChars(HttpServletRequest request) {

        BufferedReader br = null;
        StringBuilder sb = new StringBuilder("");
        try {
            br = request.getReader();
            String str;
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            br.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != br) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return sb.toString();
    }

}

 

 The configuration of coding+webhook to realize the automatic refresh of springcloud configuration center has been completed. As one of the five major components of springcloud, the springcloud configuration center must be mastered. I believe we will go farther and higher on the road of programming.

If there are omissions or errors in the article, please comment and leave a message for discussion. The code word is not easy, just like it

Guess you like

Origin blog.csdn.net/nienianzhi1744/article/details/108530142