创建项目
服务提供方
1. Spring Initializr 创建Spring Boot项目
2. 填写项目信息
3. 添加Web依赖
4. mybatis依赖
配置文件
server:
port: 8082
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb1?useUnicode=true&characterEncoding=utf8
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
application:
name: user-service # 应用名称
main:
allow-bean-definition-overriding: true #当遇到同样名字的时候,是否允许覆盖注册
# druid:
# initial-size: 1
# min-idle: 1
# max-active: 20
# test-on-borrow: true
# stat-view-servlet:
# allow: true
#
eureka:
client:
service-url: # EurekaServer地址
defaultZone: http://127.0.0.1:10086/eureka
# 实例的配置信息
instance:
prefer-ip-address: true # 当调用getHostname获取实例的hostname时,返回ip而不是host名称
ip-address: 127.0.0.1 # 指定自己的ip信息,不指定的话会自己寻找
此处编写的是服务提供方. 提供根据ID查询用户信息的功能
看yml最后的语法是eureka 配置信息的.
但是我们的这个eureka配置却没有使用到.
原因是因为我们这个提供方的查询RESTAPI是硬编码到程序中的.之后我们将会修正
此处项目还是传统项目
服务调用方
1. Spring Initializr 创建Spring Boot项目
2. 填写项目信息
3. 添加Web依赖
流程
服务调用方 是根据 提供方提供的RESTAPI 去 调用服务提供方的资源, 来查询用户信息.
但是我们的调用地址确是写死的.直接下载程序中了.
所以我们需要使用Eureka 动态的获得 提供方的API.来获得数据
总结
在consumer中,我们把url地址硬编码到了代码中,不方便后期维护
服务调用方 需要记忆 服务提供方 的地址,如果出现变更,可能得不到通知,地址将失效
服务调用方 不清楚 服务提供方 的状态,服务宕机也不知道
服务提供方 只有1台服务,不具备高可用性
即便 服务提供方 形成集群,服务调用方 还需自己实现负载均衡
其实上面说的问题,概括一下就是分布式服务必然要面临的问题:
服务管理
如何自动注册和发现
如何实现状态监管
如何实现动态路由
服务如何实现负载均衡
服务如何解决容灾问题
服务如何实现统一配置
服务调用方不需要yml文件的配置,只需要使用Http的方式调用服务提供方的API即可
Eureka
概述:
Eureka就好比是滴滴,负责管理、记录服务提供者的信息。
服务调用者无需自己寻找服务,而是把自己的需求告诉Eureka,然后Eureka会把符合你需求的服务告诉你。
同时,服务提供方与Eureka之间通过 “心跳” 机制进行监控.
当某个服务提供方出现问题,Eureka自然会把它从服务列表中剔除。
这就实现了服务的自动注册、发现、状态监控。
Eureka注册中心
1. 在SpringBoot的基础上引入 Eureka 的依赖
2. 在 启动类上使用 @EnableEurekaServer 开启 eureka 服务
3. 配置 yml 信息
此处创建的是 eureka 注册中心
添加的POM信息:
<!-- Eureka服务端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- SpringCloud版本,是最新的F系列 -->
<spring-cloud.version>Finchley.RC1</spring-cloud.version>
<dependencyManagement>
<dependencies>
<!-- SpringCloud依赖,一定要放到dependencyManagement中,起到管理版本的作用即可 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
server:
port: 10086 # 端口
spring:
application:
name: eureka-server # 应用名称,会在Eureka中显示
eureka:
client:
register-with-eureka: false # 是否注册自己的信息到EurekaServer,默认是true
fetch-registry: false # 是否拉取其它服务的信息,默认是true
service-url: # EurekaServer的地址,现在是自己的地址,如果是集群,需要加上其它Server的地址。
defaultZone: http://127.0.0.1:${server.port}/eureka
defaultZone: 地址 代表的是 eureka注册中心 界面的访问地址. 打开就可看到页面
服务提供方
将服务提供方改成 eureka 提供服务,并注册到 eureka 注册中心
1. 添加POM 依赖
2. 添加注解
3. 编写配置信息
<!-- SpringCloud的依赖 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.RC1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!-- Spring的仓库地址 -->
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<!-- Eureka客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
@SpringBootApplication
@EnableDiscoveryClient // 开启EurekaClient功能
public class UserServiceDemoApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceDemoApplication.class, args);
}
}
server:
port: 8081
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb1?useUnicode=true&characterEncoding=utf8
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
application:
# 这里我们添加了spring.application.name属性来指定应用名称,将来会作为应用的id使用。
name: user-service # 应用名称
# druid:
# initial-size: 1
# min-idle: 1
# max-active: 20
# test-on-borrow: true
# stat-view-servlet:
# allow: true
eureka:
client:
# 不用指定register-with-eureka和fetch-registry,因为默认是true
register-with-eureka: true
fetch-registry: true
service-url: # EurekaServer地址
defaultZone: http://127.0.0.1:10086/eureka
instance:
prefer-ip-address: true # 当调用getHostname获取实例的hostname时,返回ip而不是host名称
ip-address: 127.0.0.1 # 指定自己的ip信息,不指定的话会自己寻找
注意:服务提供方和服务调用方的yml配置,在最后的 instance 是不一样的.
user-service是配置了 instance 信息的, 而服务调用方则没有.
这是因为, 调用方直接面向的是用户, 而提供方则面向的是 调用方.
服务调用方
修改服务调用方 的调用方式:
@Service
public class UserService {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;// Eureka客户端,可以获取到服务实例信息
public List<User> queryUserByIds(List<Long> ids) {
List<User> users = new ArrayList<>();
// String baseUrl = "http://localhost:8081/user/";
// 根据服务名称,获取服务实例
List<ServiceInstance> instances = discoveryClient.getInstances("user-service");
// 因为只有一个UserService,因此我们直接get(0)获取
ServiceInstance instance = instances.get(0);
// 获取ip和端口信息
String baseUrl = "http://"+instance.getHost() + ":" + instance.getPort()+"/user/";
ids.forEach(id -> {
// 我们测试多次查询,
users.add(this.restTemplate.getForObject(baseUrl + id, User.class));
// 每次间隔500毫秒
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
return users;
}
}