background

In some projects with freemarker or jsp as the template engine spring mvc project development process, services in different environments are usually jointly debugged locally, after all, deployed online Debugging is extremely inconvenient. This article will take the actual project as an example to clarify each link of the request and how to switch to a different environment.

process

Take the agentBuy(Spring MVC) project as an example, sort out the page accessed from the browser to the server controller layer receives the request and calls service layer service or remote service call, Access redis , check the library MySQL , consume the message, and finally inject the business data into the template, which is compiled by the engine into html and returned to the browser for rendering.

本地联调不同测试环境.png

  • agentBuy-service服务是Spring MVC服务, controller层接收到请求后,可能调用自身service服务或者其他远程service Service obtains business data injection ftl template, and then freemarker the engine compiles the template into html and returns it to the browser for rendering. The business data of this process may come from redis cache, or MySQL database, or ES ;
  • Browser loading and parsing html may be pulled in the process CassEC-Static static resources on the static resource service;
  • After the page is loaded, other web services may be requested during the interaction to obtain business data;
  • After the page is loaded, message-service the message service may also push messages to the browser;

All the above processes go by default alpha environment configuration, if you want to local joint debugging hwbeta , gamma environment, you need to figure out the calling process and configuration of each link .

remote service call

Spring Cloud core components: Eureka

Suppose now that an e-commerce website is developed, agentBuy-service needs to obtain the user address from inquiry-service , but agentBuy-service does not know that the service it depends on is on that machine. Even if he wants to initiate a request, he doesn't know who to send it to, and he is powerless!

At this time, it was the turn of Spring Cloud Eureka to play. Eureka is the registration center in the microservice architecture, which is responsible for the registration and discovery of services. Its official structure diagram is as follows:

eureka.png

Spring-Cloud Euraka is a component in the Spring Cloud set, which is an integration of Euraka for service registration and discovery. Eureka is an open source framework in Netflix . zookeeperConsul一样,都是用于服务注册管理的,同样, Spring-Cloud Zookeeper Consul .

Eureka consists of multiple instance (service instances), which can be divided into two types: Eureka Server and Eureka Client For ease of understanding, we subdivide ---1f223d49a06691191feabf231fd4a094 Eureka client into Service Provider and Service Consumer .

  • Eureka Server is the service registration center, which exposes its own address, is responsible for managing and recording the information of service providers, and returns the address list of service providers that meet the requirements to service consumers
  • Service Provider is a service provider. After the service is started, the service provider registers its own IP Eureka port, service and other information with ---e8aec4526c8a259962d5de7274172c6d---, and continues to provide services and other information regularly. update your status etc.
  • Service Consumer is a service consumer, find the provider address information of the required service through Eureka Server , and then initiate a remote call to the service provider

Eureka (1).png

agentBuy-service is a Spring MVC service, you don't need to provide services to other services, and you don't need to register yourself to Eureka Server , you only need to serve as Service Consumer Call other remote services. agentBuy-service Configure the consumer service as follows:

(1) Add Eureka-client dependency to the pom file

 <dependency>
  <groupId>com.netflix.eureka</groupId>
  <artifactId>eureka-client</artifactId>
  <exclusions>
    <exclusion>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
    </exclusion>
  </exclusions>
</dependency>

(2) Add related configuration information in the eureka-client.properties configuration file, the settings do not need to be registered to Eureka Server , add eureka.registration.enabled=false and eureka.registerWithEureka=false as follows:

 // eureka-client.properties
###Eureka Client configuration for Sample Eureka Client

# see the README in eureka-examples to see an overview of the example set up

# note that for a purely client usage (e.g. only used to get information about other services,
# there is no need for registration. This property applies to the singleton DiscoveryClient so
# if you run a server that is both a service provider and also a service consumer,
# then don't set this property to false.
eureka.registration.enabled=false # 表示是否注册到Eureka Server,默认为true

## configuration related to reaching the eureka servers
eureka.preferSameZone=true
eureka.shouldUseDns=false
eureka.registerWithEureka=false # 表示是否将自己注册到Eureka Server,默认为true

eureka.serviceUrl.default=http://10.118.71.204:8761/eureka/ # 注册中心地址

eureka.appinfo.replicate.interval=10

eureka.vipAddress=agentbuy-service # 定义服务名变量
eureka.name=${eureka.vipAddress} # 服务名,SpringCloud中服务调用的依据
eureka.port=8001 # 服务端口
#eureka.ipAddr=192.168.29.170
#eureka.instanceId=${eureka.vipAddress}:${eureka.port}
#eureka.hostname=${eureka.ipAddr}
eureka.homePageUrlPath=/${eureka.vipAddress}
#eureka.statusPageUrlPath=/${eureka.vipAddress}/status
#eureka.healthCheckUrlPath=/${eureka.vipAddress}/health
eureka.lease.renewalInterval=5
eureka.lease.duration=15
eureka.decoderName=JacksonJson

Spring Cloud core components: Feign

agentBuy-service also integrates Feign implementing the definition of dependent service interface. Under the implementation of Spring Cloud feign , it is only necessary to create an interface and configure it with annotations to complete the interface binding of the service provider, which simplifies the use of Spring Cloud Ribbon to encapsulate the service call by itself The amount of client development. You don't need to write a lot of code yourself, establish a network connection with other services, then construct a complex request, then send the request, and finally write a lot of code to deal with the returned response.

This is the code snippet of the above process translation, let's take a look and experience this desperate and helpless feeling! ! !

img

After reading the large piece of code above, did you feel a chill on your back and a cold sweat? In fact, when you make an inter-service call, if you write code every time, the amount of code is at least several times larger than the above paragraph, so this is not something that people on earth can do.

Feign has already provided us with an elegant solution. Let's see if you use Feign , what will the code of your order service call inventory service look like?

img

How do you feel after reading the code above? Do you feel that the whole world is clean, and you have found the courage to live again! There is no underlying code for establishing a connection, constructing a request, and parsing a response, just use annotations to define an F eignClient interface, and then call that interface. People Feign Client will establish a connection with the service you specify, construct a request, initiate a request, get a response, parse the response, and so on according to your annotations at the bottom layer. This series of dirty work has been done by others Feign for you.

So the question is, how did Feign achieve such magic? Quite simply, a key mechanism of Feign is the use of dynamic proxies. Let's take a look at the following figure and analyze it in combination with the figure:

  • First, if you define a @FeignClient annotation for an interface, Feign will create a dynamic proxy for this interface
  • Then if you call that interface, the essence is to call the dynamic proxy created by Feign , which is the core of the core.
  • The dynamic proxy of Feign 57ea4fe53b7de2f0afcc537afe12a4cb--- will dynamically construct the address of the service you want to request according to your annotations on the interface such as @RequestMapping
  • Finally, for this address, initiate a request and parse the response

Feign.png

agentBuy-service集成Spring MVC web项目, bean @Autowired注入实例, but agentBuy-service to generate inquiry-service Feign the interface instance injection to initiate a remote call, cannot use @Autowired bean “Could not autowire. No beans of 'InquiryClient' type found” ,所以项目中使用---cfc594025484c3381f644aab7e86ade2 FeignClientBuilder动态创建---e54933dad54e2a8ad681ffc49c678c07---实例发起远程服务请求,缺陷是每次都FeignClient , It is then destroyed after the scope's lifetime ends.

Spring Boot 07a50fc03acfd4ee3e623c1c73af26cb---在启动类中使用了@SpringBootApplication 16a1071db07b83d37a60a89d7edd2668--- ,其内部封装了@ComponentScan , @EnableAutoConfiguration , @SpringBootConfiguration

  • @ComponentScan用来自动扫描被这些注解( @Service , @Repository , @Component , @Controller )标识class, and finally generate IOC in the container bean
  • @SpringBootConfiguration Used to declare that the current class is a configuration class, which can be generated by @Bean annotation IOC container managed bean
  • @EnableAutoConfiguration is Spring Boot the core annotation for automatic configuration, through which spring the beans required by the application are injected into the container. @EnableAutoConfiguration The source code passed @Import injected an implementation class of ImportSelector
    AutoConfigurationImportSelector , this ImportSelector finally implements the required dynamic loading according to our configuration bean

So, inject the instance with @Autowired

Reference: Briefly talk about @SpringBootApplication

In addition, if you specify FeignClientBuilder in the class configAgentUrl property (remote service address) when generating bean , then you can locate the service across Eureka It needs to be located by Eureka ). Spring Boot Service Feign interface configuration does not specify the url address for the service call, and the service name is specified, so that if the relying party service wants to call Feign interface must be registered in the same registry as the relying party service

动态FeignClientBuilder.png

feign接口.png

bean.png

carbon (3).png

carbon (1).png

Spring Cloud Core Components: Ribbon

Finished Feign , not finished yet. Now the new problem comes again, if people's inventory service is deployed on 5 machines, as shown below:

  • 192.168.169:9000
  • 192.168.170:9000
  • 192.168.171:9000
  • 192.168.172:9000
  • 192.168.173:9000

Here's to trouble! People Feign How do you know which machine to request?

This is Spring Cloud Ribbon comes in handy. Ribbon is designed to solve this problem. Its function is load balancing, which will help you select a machine for each request and distribute the request evenly to each machine

Ribbon load balancing uses the most classic Round Robin polling algorithm by default. what is this? Simply put, if the order service makes 10 requests to the inventory service, then let you request the first machine, then the second machine, the third machine, the fourth machine, the fifth machine, and then One more cycle, 1st machine, 2nd machine. . . And so on.

In addition, Ribbon is working closely with Feign and Eureka to complete the work as follows:

  • First of all Ribbon will get the corresponding service registry from Eureka Client , and also know which machines all services are deployed on and which port numbers are listening.
  • Then Ribbon can use the default Round Robin algorithm to select a machine
  • Feign will construct and initiate a request for this machine.

Take the order service remotely calling the inventory service as an example, describe the synergy between Eureka , Ribbon , Feign :

Eureka、Ribbon、Feign三者之间的关系.png

Reference: One article to understand the relationship between SpringCloud and Eureka, Feign, Ribbon, Hystrix, Zuul core components

case

[Maintenance shop side] Purchase confirmation page

The purchase confirmation page is agentBuy-service Spring MVC the page in the project. The calling process is relatively complicated. Take this as an example to explain how to switch to other environments for joint debugging locally. Overall, the following configuration changes are required:

(1) Go to the local gateway and modify the gateway configuration

routes.yml following configuration

image-20220111183527675.png

(2) agentBuy may call other service layer service , the default will call alpha environment hwbeta service service need to switch to hwbeta Environmental intranet domain name

agentBuy-service FeignClientBuilder动态创建---dfcf2a80ab592ebfccb20e46a3cce47f FeignClient实例去发起远程调用, bean时指定FeignClientBuilderconfigAgentUrl , you can call the service across Eureka , do not need to pass Eureka Server location service

common.yml following configuration:

image2022-1-5_15-56-10.png

image-20220111184644237.png

image-20220111183800956.png

(3)在页面交互过程还可能请求其他web服务web服务可能又调用了其他service服务( spi ), this process needs to change the gateway routing configuration, so that the page request is forwarded to the local web service, web service engineering also needs to change the configuration to make it call hwbeta service service, the following uses web-market as an example to change the configuration:

 # webagent/config/routes.yml
- id: web-market
  predicates:
      - Path=/market/**
  #uri: 'lb://web-market'
  uri: 'http://localhost:9801' # 改成走本地web-market服务

web-market The environment variable is pulled config-center Configuration project, so you only need to change the environment variable spring.profiles.active=hwbeta , enable the hwbeta configuration of the environment

 # bootstrap.yml
server:
  port: 9801
  contextPath: /market
  tomcat:
    protocolHeader: X-Forwarded-Proto
encrypt.failOnError: false
spring:
  application:
    name: web-market
  cloud:
    config:
      uri: http://config-center.alpha-intra.casstime.com/conf
      label: alpha
management:
  port: 29801
  contextPath: /hellgate
  security.enabled: false
xmwlServiceUrl: https://xmwltest.casstime.com/edi/kaisi/getLogisticOrderTrace
wenjuanxing.key: 8560a160-d42b-40d6-a97e-48b12cf51e8b
---
spring:
  profiles: hwbeta
  cloud:
    config:
      uri: http://config-center.hwbeta-intra.casstime.com/conf # 改成去配置中心服务拉取hwbeta的配置,里面包含Eureka Server注册中心的地址
      label: hwbeta

---
spring:
  profiles: prod
  cloud:
    config:
      uri: http://config-server.intra.cassmall.com/conf
      label: master
xmwlServiceUrl: https://xmwl.cassmall.com/edi/kaisi/getLogisticOrderTrace

(4) The server may also access the cache redis , so the configuration of the connection redis also needs to be changed

image-20220725160631278.png

(5) The server will also access the database , so the configuration of the connection MySQL also needs to be changed

image-20220725003603103.png

(6) Gateway default call alpha environment service OAuth2.0 authorized login , also need to switch to hwbeta environment

image-20220725160826820.png

(7) Pull CassEC-Static static resources

image-20220729140026271.png

【Supplier side】Quote page

The quotation page is also special. There is a seller-center abnormal gateway service between webagent and agentBuy , and the service will provide卖家中心slidertopbarfooter公共模块,用sitemesh agentBuy中的内容页面

(1) Change the gateway configuration

config/routes.yml

image2021-4-8_17-48-58.png

image2021-4-8_17-43-43.png

 # 注意与保持上下文的缩进
...
      - id: sellerMgr
        predicates:
        - Path=/sellerMgr/**, /storemgr/**, /casswallet/seller/**, /bill/seller/**, /invoice/seller/**, /scf/seller/**, /orders/seller/**, /member/seller/**
        uri: 'lb://sellercenter-portal'
      - id: sellerMgr2
        predicates:
        - Path=/agentBuy/seller/**
        # uri: 'lb://sellercenter-portal'
        uri: 'http://localhost:10102'
...

Purpose:

  1. sellerMgr Split out two items (with different id names), and let the requests of agentBuy/seller/** be routed to the locally started seller-center service; let other unrelated requests be routed Deployed to the test environment seller-center . Make other information such as the sidebar display normally.
  2. agentbuy-serviceuri改为本地服务地址+端口,使除agentBuy/seller/**外的其他的agentBuy/**本地的agentBuy In service.

(2) seller-center Project configuration

image2021-4-8_17-23-8.png

 zuul.routes.agentBuy.url=http://localhost:8001
Purpose: Let the request that passed through agentBuy/seller/** seller-center routed to the local agentBuy service through the local ---563b98be48ee085f2e638a2a64e0e8b8---.

Disadvantages of local joint debugging of other environments

Local joint debugging hwbeta、gamma environment will lead to environmental pollution. The following two scenarios are used as examples to illustrate:

(1) hwbeta环境,本地agentBuy-service能调通hwbeta环境的远程服务quote-service ,当quote-service Send a message push, and then the local agentBuy-service will receive the message and consume the message. If this message indicates that the supplier quotation is complete, agentBuy-service need to change the status of the inquiry form in the shoppinglist table to quotation complete after receiving this message, but if the local connection alpha Environmental database, the inquiry order cannot be found at this time, and its quotation status cannot be changed, and the correct status of the inquiry order should be that the quotation is completed, but the actual quotation is not completed, resulting in hwbeta Environmental data is polluted.

本地联调其他环境的缺点.png

(2) agentBuy-service 1a1f0d919a98d4b9d392440fe8791102---依赖了web-seller web-market web服务, web-seller远程调用了A服务, web-market远程调用了B服务,但是本地联调只更改了---0173c0b016146893ad3f3cfce14dac74 web-seller A服务The remote call address ( hwbeta ), without changing web-market points to B , causing the service remote address (still alpha ) Part of the input data comes from ---b29e3d5884e7e33f8b17be30830735f2 alpha , and some data comes from hwbeta , so the written data is wrong, hwbeta the environment is also polluted.

hwbeta , gamma environment is similar to a sandbox, almost completely isolated, which ensures the reliability of the test. Once the environment is polluted, the reliability of the test results in this environment cannot be obtained. Guaranteed, so it is not recommended that you use the above method to conduct local joint debugging


记得要微笑
1.9k 声望4.5k 粉丝

知不足而奋进,望远山而前行,卯足劲,不减热爱。