Eureka
1.1.原理图(重要)
原理说明
Eureka:就是服务注册中心(可以是一个集群),对外暴 露自己的地址
提供者:启动后向Eureka注册自己信息(地址,提供什么服务)
消费者:向Eureka订阅服务,Eureka会将对应服务的所有提供者地址列表发送给消费者,并且定期更新
心跳(续约):提供者定期通过http方式向Eureka刷新自己的状态
1.2.快速上手
环境:
通过SpringBoot搭建
eureka-server 注册中心
user-service 服务提供者(生产者)
user-consumer 消费者
实现过程:
在环境搭建好之后,eureka_cr-server启动后对外提供自己的IP地址(暴露地址)
user_cr-service通过eureka_cr-server提供的IP地址将自己的信息注册到eureka_cr-server中,并定期通过http请求刷新自己的状态,
user_cr-consume订阅注册中心中的服务,并定期通过服务的名称(服务的名称指的是消费者的名称,即application.name)获取到所有对应的服务地址列表(提供者的地址列表),调用提供者的服务
1.eureka_cr-server(注册中心)
创建项目:
1.使用脚手架创建SpringBoot项目
2.填写好项目的信息,点击next
4.选择依赖,自动导入依赖,next --> finish
注意:如果没有采用自动选择依赖,需要自己在pom文件中手动添加依赖
<!--Eureka注册中心--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
项目创建好后:
1.在启动类上添加 @EnableEurekaServer该注解的作用是开启注册中心服务
package com.czxy; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication //开启EurekaServer @EnableEurekaServer public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } }
2.将application.properties改成application.yml,在yml文件中添加注册中心相关的配置
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
3.ok,EurekaServer就编写完了
2.user_cr-service(提供者)
创建项目
1.在原项目的基础上,右键点击创建选择new project
2.使用脚手架创建SpringBoot项目
3.填写好项目的信息后直接next
4.什么都不用选择直接next
5.他是单独的一个项目,记得要删除他的上级文件名,如图所示(参考)
项目创建好后配置:
1.在pom文件中加入Eureka客户端的依赖,因为user-service是提供者,与数据库交换的,还需要引入其他相关的包(完整的)
<!-- 统一版本维护 --> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <mybatis.starter.version>1.3.2</mybatis.starter.version> <mapper.starter.version>2.0.2</mapper.starter.version> <mysql.version>5.1.32</mysql.version> <pageHelper.starter.version>1.2.5</pageHelper.starter.version> <durid.starter.version>1.1.10</durid.starter.version> </properties> <dependencies> <!-- SpringBoot整合SpringMVC的启动器 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- SpringBoot整合jdbc和事务的启动器 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!-- mybatis启动器 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>${mybatis.starter.version}</version> </dependency> <!-- 通用Mapper启动器 --> <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper-spring-boot-starter</artifactId> <version>${mapper.starter.version}</version> </dependency> <!-- 分页助手启动器 --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>${pageHelper.starter.version}</version> </dependency> <!-- mysql驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <!-- Eureka客户端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!-- Druid连接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>${durid.starter.version}</version> </dependency> </dependencies> <!-- SpringCloud的依赖 --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.RELEASE</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>
2.在项目的启动类上添加注解
package com.czxy; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication //开启 EurekaClient @EnableEurekaClient public class UserRcServiceApplication { public static void main(String[] args) { SpringApplication.run(UserRcServiceApplication.class, args); } }
3.将application.properties改成application.yml,在yml文件中添加提供者相关的配置(直接拷贝进去就可以了)
# 端口配置 server: port: 8888 # 端口 # Spring 数据连接接源配置 spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/day1203?useUnicode=true&characterEncoding=utf8 username: root password: root # 日期格式化 jackson: date-format: yyyy-MM-dd time-zone: GMT+8 mvc: date-format: yyyy-MM-dd HH:mm:ss # 生产者的名字 application: name: user-service main: allow-bean-definition-overriding: true #当遇到同样名字的时候,是否允许覆盖注册 # 设置编码类型 http: encoding: charset: UTF-8 enabled: true force: true messages: encoding: UTF-8 eureka: client: service-url: # EurekaServer地址 defaultZone: http://127.0.0.1:10086/eureka,http://127.0.0.1:10087/eureka instance: instance-id: ${spring.application.name}:${server.port} prefer-ip-address: true # 当调用getHostname获取实例的hostname时,返回ip而不是host名称 ip-address: 127.0.0.1 # 指定自己的ip信息,不指定的话会自己寻找 lease-expiration-duration-in-seconds: 2 # 如果90s内不到续约,就默认服务已经挂掉了 lease-renewal-interval-in-seconds: 1 # 每隔30s向服务器发送一次心跳(续约)
编写逻辑代码:
因为我们只是测试,所以我直接来一个根据主键ID查询对应的记录的方法
domian
package com.czxy.domain; import java.io.Serializable; import javax.persistence.*; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString; @Data @AllArgsConstructor @NoArgsConstructor @ToString @Table(name = "user") public class User implements Serializable { /** * 用户ID */ @Id @Column(name = "uid") @GeneratedValue(generator = "JDBC") private Integer uid; /** * 用户名 */ @Column(name = "username") private String username; /** * 密码 */ @Column(name = "password") private String password; /** * 性别 */ @Column(name = "sex") private String sex; /** * 年龄 */ @Column(name = "age") private Integer age; @Column(name = "remarks") private String remarks; private static final long serialVersionUID = 1L; }
dao
package com.czxy.dao; import com.czxy.domain.User; import tk.mybatis.mapper.common.Mapper; @org.apache.ibatis.annotations.Mapper public interface UserMapper extends Mapper<User> { }
servier
package com.czxy.service; import com.czxy.domain.User; import java.util.List; public interface UserService{ List<User> findUserById(List<Integer> ids); }
service-Impl
package com.czxy.service.impl; import com.czxy.domain.User; import org.springframework.stereotype.Service; import javax.annotation.Resource; import com.czxy.dao.UserMapper; import com.czxy.service.UserService; import java.util.ArrayList; import java.util.List; @Service public class UserServiceImpl implements UserService{ @Resource private UserMapper userMapper; @Override public List<User> findUserById(List<Integer> ids) { List<User> users = new ArrayList<>(); for (Integer id : ids) { users.add(userMapper.selectByPrimaryKey(id)); } return users; } }
controller
package com.czxy.controller; import com.czxy.domain.User; import com.czxy.service.UserService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import java.util.List; /** * @Author ScholarTang * @Date 2019/12/10 1:09 PM * @Desc 处理用户相关的业务 */ @Slf4j @CrossOrigin(origins = "*",maxAge = 3600) @RestController public class UserController { @Autowired private UserService service; /** * TODO 根据主键ID查询对应的记录 * @param ids * @return */ @GetMapping("/findUserById/{ids}") public ResponseEntity<List<User>> findUserById (@PathVariable(name = "ids") List<Integer> ids) { log.info("ids:{}",ids); List<User> users = service.findUserById(ids); return ResponseEntity.ok(users); } }
3.user_cr-consumer(消费者)
创建项目:
创建项目的方式与user_cr-service的创建方式一样
创建项目完成后:
1.在项目的启动类上添加@EnableEurekaClient注解或者@EnableDiscoveryClient,这两个注解的功能是一样的
package com.czxy; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication //开启EurekaClient @EnableEurekaClient public class UserCrConsumerApplication { public static void main(String[] args) { SpringApplication.run(UserCrConsumerApplication.class, args); } }
2.在pom文件中添加如下依赖
<!-- SpringBoot整合SpringMVC的启动器 RestTemplate包所在依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Eureka客户端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
3.将application.properties改成application.yml,在yml文件中添加消费者相关的配置
server: port: 8889 spring: application: name: user-consumer # 应用名称 # # 设置编码类型 http: encoding: charset: UTF-8 enabled: true force: true messages: encoding: UTF-8 cloud: loadbalancer: retry: enabled: true eureka: client: service-url: # EurekaServer地址 defaultZone: http://127.0.0.1:10086/eureka registry-fetch-interval-seconds: 5 instance: prefer-ip-address: true # 当其它服务获取地址时提供ip而不是hostname ip-address: 127.0.0.1 # 指定自己的ip信息,不指定的话会自己寻找 instance-id: ${spring.application.name}:${server.port} lease-expiration-duration-in-seconds: 2 # 如果90s内不到续约,就默认服务已经挂掉了 lease-renewal-interval-in-seconds: 1 # 每隔30s向服务器发送一次心跳(续约) user-service: ribbon: # NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡(随机) ConnectTimeout: 250 # Ribbon的连接超时时间 ReadTimeout: 1000 # Ribbon的数据读取超时时间 OkToRetryOnAllOperations: true # 是否对所有操作都进行重试 MaxAutoRetriesNextServer: 1 # 切换实例的重试次数 MaxAutoRetries: 1 # 对当前实例的重试次数
编写逻辑代码:
简单的调研提供者中的接口
configpackage com.czxy.config; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.web.client.RestTemplate; import java.nio.charset.Charset; /** * @Author ScholarTang * @Date 2019/12/10 3:20 PM * @Desc RestTemplate配置类 */ @Configuration public class RestTemplateConfig { /** * 将RestTemplate对象交给Spring容器管理 * * @return */ @Bean public RestTemplate restTemplate() { RestTemplate restTemplate = new RestTemplate(); restTemplate.getMessageConverters().add(new StringHttpMessageConverter(Charset.forName("UTF-8"))); return restTemplate; } }
controller
package com.czxy.controller; import com.alibaba.fastjson.JSON; import org.apache.catalina.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import java.util.List; /** * @Author ScholarTang * @Date 2019/12/10 3:21 PM * @Desc */ @RestController public class GetDataController { @Autowired private RestTemplate restTemplate; @Autowired private DiscoveryClient discoveryClient; /** * 服务调用,测试接口 * @param ids * @return */ @GetMapping("/findUserById/{ids}") public ResponseEntity<List<User>> findUserById (@PathVariable(name = "ids") String ids) { //根据服务的名称,获取对应的所以提供者服务的地址列表 List<ServiceInstance> instances = discoveryClient.getInstances("user-service"); //拿到第一个 ServiceInstance instance = instances.get(0); //拼接url String url = instance.getUri() + "/" + ids; String usersByJsonData = restTemplate.getForObject(url, String.class); List<User> users = (List<User>) JSON.parse(usersByJsonData); return ResponseEntity.ok(users); } }
domain
package com.czxy.domain; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString; /** * @Author ScholarTang * @Date 2019/12/10 3:22 PM * @Desc 用户类 */ @Data @AllArgsConstructor @NoArgsConstructor @ToString public class User { /** * 用户ID */ private Integer uid; /** * 用户名 */ private String username; /** * 密码 */ private String password; /** * 性别 */ private String sex; /** * 年龄 */ private Integer age; private String remarks; }
4.启动服务器测试
1.先开启注册中心的服务
2.接着时服务提供者
3.最后是消费者
4.服务都开启后访问http://localhost:10086,如图所示,说明提供者和消费者都注册到EurekaService中了
5.调用服务测试接口