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.
-
agentBuy-service
服务是Spring MVC
服务,controller
层接收到请求后,可能调用自身service
服务或者其他远程service
Service obtains business data injectionftl
template, and thenfreemarker
the engine compiles the template intohtml
and returns it to the browser for rendering. The business data of this process may come fromredis
cache, orMySQL
database, orES
; - Browser loading and parsing
html
may be pulled in the processCassEC-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:
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
. zookeeper
、 Consul
一样,都是用于服务注册管理的,同样, 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 ownIP
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 throughEureka Server
, and then initiate a remote call to the service provider
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! ! !
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?
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
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 generateIOC
in the containerbean
-
@SpringBootConfiguration
Used to declare that the current class is a configuration class, which can be generated by@Bean
annotationIOC
container managedbean
-
@EnableAutoConfiguration
isSpring Boot
the core annotation for automatic configuration, through whichspring
the beans required by the application are injected into the container.@EnableAutoConfiguration
The source code passed@Import
injected an implementation class ofImportSelector
AutoConfigurationImportSelector
, thisImportSelector
finally implements the required dynamic loading according to our configurationbean
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
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 fromEureka Client
, and also know which machines all services are deployed on and which port numbers are listening. - Then
Ribbon
can use the defaultRound 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
:
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
(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
时指定FeignClientBuilder
中configAgentUrl
, you can call the service across Eureka
, do not need to pass Eureka Server
location service
common.yml
following configuration:
(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
(5) The server will also access the database , so the configuration of the connection MySQL
also needs to be changed
(6) Gateway default call alpha
environment service OAuth2.0
authorized login , also need to switch to hwbeta
environment
(7) Pull CassEC-Static
static resources
【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卖家中心slider
、 topbar
、 footer
公共模块,用sitemesh
agentBuy
中的内容页面
(1) Change the gateway configuration
config/routes.yml
# 注意与保持上下文的缩进
...
- 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:
sellerMgr
Split out two items (with different id names), and let the requests ofagentBuy/seller/**
be routed to the locally startedseller-center
service; let other unrelated requests be routed Deployed to the test environmentseller-center
. Make other information such as the sidebar display normally.agentbuy-service
的uri
改为本地服务地址+端口,使除agentBuy/seller/**
外的其他的agentBuy/**
本地的agentBuy
In service.
(2) seller-center
Project configuration
zuul.routes.agentBuy.url=http://localhost:8001
Purpose: Let the request that passed throughagentBuy/seller/**
seller-center
routed to the localagentBuy
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.
(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
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。