目录
一、Eureka概述
官方的介绍在这里Eureka wiki。
Eureka是 Netflix的一个子模块,也是核心模块之一。Eureka是一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移。
服务注册与发现对于微服务架构来说是非常重要的,有了服务发现与注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了。功能类似于dubbo的注册中心Zookeeper。
二 、Eureka原理讲解
1、三大角色
- Eureka Server 提供服务注册和发现。
- Service Provider 服务提供方将自身服务注册到Eureka,从而使服务消费方能够找到。
- Service Consumer 服务消费方从Eureka获取注册服务列表,从而能够消费服务。
2、Eureka基本架构
Spring Cloud封装了Netflix公司开发的Eureka模块来实现服务注册和发现。
Eureka采用CS的设计架构。EurekaServer作为服务注册功能的服务器,它是服务注册中心。而系统中的其他微服务,使用Eureka的客户端连接到EurekaServer并持续心跳连接。这样系统的维护人员就可以通过EurekaServer来监控系统中各个微服务是否正常运行。SpringCloud的一些其他模块(比如Zuul)就可以通过EurekaServer来发现系统中的其他微服务,执行相关的逻辑。
Eureka是Netflix开源的一个RESTful服务,主要用于服务的注册发现。
Eureka包含两个组件:Eureka Server和Eureka Client。
Eureka Server提供服务注册服务,各个节点启动后,会在EurekaServer中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
Eureka Client是一个java客户端,用于简化EurekaServer的交互,客户端同时也具备一个内置的,使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向EurekaServer发送心跳(默认周期30秒)。如果EurekaServer在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移出(默认90秒)
三、搭建Eureka服务注册中心
1、pom
主要添加eureka服务端依赖:
<!–eureka-server服务端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud-demo</artifactId>
<groupId>com.lin</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-eureka-7001</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--eureka-server服务端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<!-- 修改后立即生效,热部署 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
2、application.yml
server:
port: 7001
eureka:
instance:
hostname: localhost #eureka服务端的实例名称(相当于主机名)
prefer-ip-address: true #如我们不想使用主机名来定义注册中心的地址,也可以使用IP地址的形式, 但是需要在 配置文件中增加配置参数eureka.instance.prefer-ip-address= true, 该值默认为false。
lease-renewal-interval-in-seconds: 30 #参数用于定义服务续约任务的调用间隔时间,默认为30秒
lease-expiration-duration-in-seconds: 90 #参数用于定义服务失效的时间,默认为90秒
client:
register-with-eureka: false #false表示不向注册中心注册自己
fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
#设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址(单机)。
registry-fetch-interval-seconds: 30 #缓存清单的更新时间,默认是30秒
server:
enable-self-preservation: true #由于本地调试很容易触发注册中心的保护机制, 这会使得注册中心维护的服务实例不那么准确,默认为true。
#因此在本地调试的适合我们将参数设置为false,那么每次我们关闭客户端的时候我们的注册中心就直接移开相应的程序
3、EurekaServer7001_App 主启动类 添加注解@EnableEurekaServer
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer // EurekaServer服务器端启动类,接受其它微服务注册进来
public class EurekaServer7001_App {
public static void main(String[] args) {
SpringApplication.run(EurekaServer7001_App.class, args);
}
}
4、启动Eureka注册中心测试是否成功
5、还可对注册中心增加密码验证
(1)pom
<!-- 增加访问eureka server的时候的权限拦截功能,防止任意的用户可用访问到我们的注册中心-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
(2)application.yml
security: # eureka注册中心增加密码验证
user:
name: lin
password: lin
(3)测试
访问 http://localhost:7001
需输入用户名密码
四、将已有的部门微服务提供者注册进Eureka服务中心(修改springcloud-provider-8001)
1、修改pom文件
- 修改部分
<!-- 将微服务provider注册进eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka<</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
- 完整部分
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud-demo</artifactId>
<groupId>com.lin</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-provider-8001</artifactId>
<dependencies>
<!-- 引入自己定义的api通用包,可以使用Dept部门Entity -->
<dependency>
<groupId>com.lin</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- 将微服务provider侧注册进eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.3.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- 修改后立即生效,热部署 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>
2、父工程的maven依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lin</groupId>
<artifactId>springcloud-demo</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.16.18</lombok.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.9.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.0.4</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.31</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<modules>
<module>springcloud-api</module>
<module>springcloud-provider-8001</module>
<module>springcloud-consumer-80</module>
<module>springcloud-eureka-7001</module>
</modules>
</project>
3、application.yml
- 修改部分
eureka:
client: #客户端注册进eureka服务列表内
service-url:
defaultZone: http://localhost:7001/eureka
- 完整部分
server:
port: 8001
mybatis:
config-location: classpath:mybatis.xml # mybatis配置文件所在路径
type-aliases-package: com.lin.entity # 所有Entity别名类所在包
mapper-locations:
- classpath:com/lin/mapper/*.xml # mapper映射文件
spring:
application:
name: springcloud-demo #对外暴露的微服务名字
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包
url: jdbc:mysql://localhost:3306/cloud01 # 数据库名称
username: root
password: root
dbcp2:
min-idle: 5 # 数据库连接池的最小维持连接数
initial-size: 5 # 初始化连接数
max-total: 5 # 最大连接数
max-wait-millis: 200 # 等待连接获取的最大超时时间
eureka: #客户端注册进eureka服务列表内
client:
service-url:
defaultZone: http://localhost:7001/eureka
instance:
instance-id: springcloud-dept-8001 #修改服务器名称显示
prefer-ip-address: true #访问路径可以显示IP地址
info: #微服务info内容详细信息修改
app.name: springcloud-dept
company.name: www.lin.com
build.artifactId: $project.artifactId$
build.version: $project.version$
4、修改主启动类Provider8001_App 添加注解@EnableEurekaClient
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient //本服务启动后会自动注册进eureka服务中
@EnableDiscoveryClient //服务发现
public class Provider8001_App {
public static void main(String[] args) {
SpringApplication.run(Provider8001_App.class,args);
}
}
5、测试
启动eurekaserver
查看服务注册侧状态: http://localhost:7001
6、dao和mapper
import com.lin.entity.Dept;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface DeptDao {
public boolean addDept(Dept dept);
public Dept findById(Long dpno);
public List<Dept> findAll();
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lin.dao.DeptDao">
<select id="findById" resultType="Dept" parameterType="Long">
select dpno,dname,dbsource from dept where dpno=#{dpno};
</select>
<select id="findAll" resultType="Dept">
select dpno,dname,dbsource from dept;
</select>
<insert id="addDept" parameterType="Dept">
INSERT INTO dept VALUES(#{dpno},#{dname},DATABASE());
</insert>
</mapper>
7、service层
import com.lin.entity.Dept;
import java.util.List;
public interface DeptService {
public boolean add(Dept dept);
public Dept get(Long id);
public List<Dept> list();
}
@Service
public class DeptServiceImpl implements DeptService {
@Autowired
private DeptDao deptDao;
@Override
public boolean add(Dept dept)
{
return deptDao.addDept(dept);
}
@Override
public Dept get(Long id)
{
return deptDao.findById(id);
}
@Override
public List<Dept> list()
{
return deptDao.findAll();
}
}
8、controller
import com.lin.entity.Dept;
import com.lin.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
public class DeptController {
@Autowired
private DeptService deptService;
@RequestMapping(value = "/dept/add", method = RequestMethod.POST)
public boolean add(@RequestBody Dept dept)
{
return deptService.add(dept);
}
@RequestMapping(value = "/dept/get", method = RequestMethod.GET)
public Dept get( Long dpno)
{
return deptService.get(dpno);
}
@RequestMapping(value = "/dept/list", method = RequestMethod.GET)
public List<Dept> list()
{
return deptService.list();
}
@Autowired
private DiscoveryClient client;
@RequestMapping(value = "/dept/discovery", method = RequestMethod.GET)
public Object discovery()
{
//盘点eureka中的微服务
List<String> list = client.getServices();
System.out.println("**********" + list);
//获取某个微服务
List<ServiceInstance> srvList = client.getInstances("springcloud-demo");
for (ServiceInstance element : srvList) {
System.out.println(element.getServiceId() + "\t" + element.getHost() + "\t" + element.getPort() + "\t"
+ element.getUri());
}
return this.client;
}
}
五、将已有的部门微服务消费者注册进eureka服务中心(修改springcloud-consumer-80)
1、pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud-demo</artifactId>
<groupId>com.lin</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-consumer-80</artifactId>
<description>部门微服务消费者</description>
<dependencies>
<!-- 自己定义的api -->
<dependency>
<groupId>com.lin</groupId>
<artifactId>springcloud-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 修改后立即生效,热部署 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!--ribbon相关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spirng-cloud-starter-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
</dependencies>
</project>
2、application.yml
server:
port: 80
spring:
application:
name: dept-consumer //服务名
eureka:
client: #客户端注册进eureka服务列表内
register-with-eureka: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka #eureka集群
3、DeptConsumer_App 入口类添加@EnableEurekaClient
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient //本服务启动后会自动注册进eureka服务中
public class DeptConsumer_App {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_App.class,args);
}
}
4、配置类
package com.lin.configbeans;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
//springboot中没有spring的applicationContext.xml ----- @Configuration配置 ConfigBean = applicationContext.xml
@Configuration //声明该类是配置类
public class ConfigBean {
@Bean
@LoadBalanced // springcloud Ribbon是基于Netflix Ribbon实现的一套客户端 负载均衡的工具。
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
//applicationContext.xml----<bean id = "userService" class = "com.lin.service.impl.UserServiceImpl">
/*
@Bean
public UserServcie getUserServcie()
{
return new UserServcieImpl();
}*/
5、controller
import com.lin.entity.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
public class DeptController_Consumer {
//private static final String REST_URL_PREFIX = "http://localhost:8001";
private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-DEMO"; //微服务的名字
/*
使用:使用restTemplate访问restful接口
(url,requestMap,ResponseBean.class) 这三个参数 分别
代表REST请求地址,请求参数,Http响应转换被转换成的对象类型
*/
@Autowired
private RestTemplate restTemplate;
@RequestMapping(value = "/consumer/dept/add")
public boolean add(Dept dept)
{
return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class);
}
@RequestMapping(value = "/consumer/dept/get")
public Dept get(Long dpno){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get?dpno="+dpno, Dept.class);
}
@SuppressWarnings("unchecked")
@RequestMapping(value = "/consumer/dept/list")
public List<Dept> list()
{
return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class);
}
// 测试@EnableDiscoveryClient,消费端可以调用服务发现
@RequestMapping(value = "/consumer/dept/discovery")
public Object discovery()
{
return restTemplate.getForObject(REST_URL_PREFIX + "/dept/discovery", Object.class);
}
}
6、测试
- 先启动EurekaServer,在启动EurekaClient 服务提供者,然后启动服务消费者。
- 查看服务注册状态:localhost:7001
- 访问consumer端服务: