服务治理是微服务架构中最为核心和基础的模块,它主要用来实现各个微服务实例的自动化注册和发现。
<<上传失败了的图片>>
Application Service 相当于服务提供者/api
Application Client 相当于服务消费者/app
Make Remote Call,其实就是实现服务的使用/比如httpClient,restTemplate
us-east-1 Eureka 集群服务
us-east-1c、us-east-1d、us-east-1e 就是具体的某个eureka
4.0.0
team.csrj
parent
1.0-SNAPSHOT
eureka-server7001
jar
eureka-server7001
eureka服务端
org.springframework.cloud
spring-cloud-starter-netflix-eureka-server
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
org.springframework.boot
spring-boot-starter-test
test
org.springframework.cloud
spring-cloud-starter-config
server:
port: 7001
spring:
application:
name: eureka-server
eureka:
client:
# 表示是否将自己注册到Eureka Server,默认为true。
register-with-eureka: false
# 表示是否从Eureka Server获取注册信息,默认为true。
fetch-registry: false
# 设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址。默认是http://localhost:8761/eureka ;多个地址可使用,分隔,后续会讲解这个路径的来源
service-url:
defaultZone: http://localhost:${server.port}/eureka/
packageteam.csrj.eurekaserver7001;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
importorg.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
publicclassEurekaServer7001Application{
publicstaticvoidmain(String[]args){
SpringApplication.run(EurekaServer7001Application.class,args);
}
}
3.1、pom.xml
4.0.0
producer-7001
服务提供者demo
team.csrj
parent
1.0-SNAPSHOT
producer-7001
jar
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
org.springframework.boot
spring-boot-starter-test
test
org.springframework.cloud
spring-cloud-starter-config
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
server:
port: 8001
servlet:
jsp:
init-parameters:
development: true
spring:
application:
name: producer-8001
profiles: dev
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
default-property-inclusion: NON_NULL
redis:
database: 1
host: ${REDIS_HOST:127.0.0.1}
port: ${REDIS_PORT:6379}
jedis:
pool:
max-active: 8
max-wait: -1ms
max-idle: 0
min-idle: 8
lettuce:
shutdown-timeout: 100ms
pool:
max-active: 8
max-wait: -1ms
max-idle: 0
min-idle: 8
datasource:
name: test
url: jdbc:mysql://${MYSQL_HOST:127.0.0.1}:${MYSQL_PORT:3306}/test
username: ----
password: ----
# 使用druid数据源
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
filters: stat
maxActive: 20
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20
messages:
encoding: UTF-8
basename: i18n/abt_messages
use-code-as-default-message: true
mvc:
view:
suffix: .html
prefix: /
servlet:
multipart:
file-size-threshold: 100mb
max-file-size: 100mb
mybatis:
basepackage: team.csrj.**.mapper
mapper-locations: ["classpath*:mapper/**/*.xml","classpath*:com/gitee/sunchenbin/mybatis/actable/mapping/*/*.xml"]
table:
auto: create
model:
pack: team.csrj
database:
type: mysql
logging:
level:
team.csrj: debug
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: ALWAYS
eureka:
client:
serviceUrl:
defaultZone: http://localhost:7001/eureka/
instance:
prefer-ip-address: true
statusPageUrlPath: /${server.servlet.context-path}/actuator/info
healthCheckUrlPath: /${server.servlet.context-path}/actuator/health
packageteam.csrj.producer;
importorg.mybatis.spring.annotation.MapperScan;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
importorg.springframework.cloud.netflix.eureka.EnableEurekaClient;
importorg.springframework.context.annotation.ComponentScan;
importorg.springframework.transaction.annotation.EnableTransactionManagement;
@SpringBootApplication
@EnableEurekaClient
@EnableTransactionManagement(proxyTargetClass=true)
@ComponentScan(basePackages={"team.csrj","com.gitee.sunchenbin.mybatis.actable.manager"})
@MapperScan({"team.csrj.**.mapper","com.gitee.sunchenbin.mybatis.actable.dao.**"})
publicclassProducerApplication{
public static void main(String[] args){SpringApplication.run(ProducerApplication.class,args);}}
由于不了解为什么客户端的defaultZone一定要加上"/eureka"这个字符串,即使服务端定义的defaultZone没有带"/eureka",客户端也必须带上,从而开始了研究eureka的部分源码。
首先通过在DiscoveryClient类中可以发现对应的注册方法 boolean register() throws Throwable,这个方法就是客户端给服务端发送注册信息的入口,我们可以看出他是通过http请求进行注册。
boolean register() throws Throwable {
logger.info(PREFIX + "{}: registering service...", appPathIdentifier);
EurekaHttpResponse httpResponse;
try {
httpResponse = eurekaTransport.registrationClient.register(instanceInfo);
} catch (Exception e) {
logger.warn(PREFIX + "{} - registration failed {}", appPathIdentifier, e.getMessage(), e);
throw e;
}
if (logger.isInfoEnabled()) {
logger.info(PREFIX + "{} - registration status: {}", appPathIdentifier, httpResponse.getStatusCode());
}
return httpResponse.getStatusCode() == 204;
}
接下来进入核心该方法里面的register(instanceInfo),通过debugger我们发现这个方法是AbstractJerseyEurekaHttpClient该类下面的方法,再进行调试,我们可以看到他是通过将"apps"和客户端的名字的大写组成urlPath,并将serviceUrl(这里的值为客户端配置文件里面的service-url.defaultZone)组合为一个url兵发送到服务端,若服务端返回204,则代表注册成功
Eureka-server的rest api是使用javax.ws实现的,及服务注册、下架等功能都是通过对应的Http请求进行执行。以下主要介绍服务注册。
Eureka-server启动过程会初始化对应的配置,其中EurekaServerAutoConfiguration配置类配置了大量的bean,我们主要了解里面的过滤器的配置。ServletContainer里面实现了jersey框架,通过他来实现eurekaServer对外的restFull接口。 从拦截路径可以看出,这些过滤器全部拦截带有“/eureka”字符串的url,我们访问eurekaServer对外的接口都必须通过这些过滤器,与上面对客户端发送的url的对比,我们发现为什么客户端的service-url.defaultZone后面的链接必须带有/eureka,不然无法成功注册,服务端也无法获取客户端的注册请求。
接下来我们在这些客户端里面找有带"/app"路径的拦截器,最终我们发现了ApplicationsResource.java.
@Bean
public FilterRegistrationBean jerseyFilterRegistration(Application eurekaJerseyApp) {
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new ServletContainer(eurekaJerseyApp));
bean.setOrder(2147483647);
bean.setUrlPatterns(Collections.singletonList("/eureka/*"));
return bean;
}
我们找到对应的ApplicationsResource类,他主要提供以下三个接口:
/{version}/apps/{appId}
/{version}/apps
/{version}/apps/delta
在eureka里面,这些{version}都是"eureka",通过客户端发送的url,我们可以找到该拦截器里面对应的注册方法
@Path("{appId}")
public ApplicationResource getApplicationResource(@PathParam("version") String version, @PathParam("appId") String appId) {
CurrentRequestVersion.set(Version.toEnum(version));
return new ApplicationResource(appId, this.serverConfig, this.registry);
}
从这个代码我们没有找到对应的注册业务逻辑,因此猜测他是将注册的业务逻辑交给了ApplicationResource.class进行。这里面的resource其实和平时的springmvc的控制层类似。