Eureka注册中心搭建
总目录结构
#### eureka-server : Eureka服务
目录结构
pom依赖
<!-- springboot web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- eureka-server --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
application.yml配置文件
server: port: 10086 eureka: client: service-url: defaultZone: http://localhost:10086/eureka instance: prefer-ip-address: true ip-address: 127.0.0.1 spring: application: name: eureka-server
EurekaServerApplication启动文件
package com.thomas.eurekaserver; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication @EnableEurekaServer public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } }
启动工程网页
user-common:公用实体类
目录结构
pom依赖
<dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper-spring-boot-starter</artifactId> <version>2.1.5</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
Country实体类
/* * The MIT License (MIT) * * Copyright (c) 2017 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.thomas.usercommon.model; import org.apache.ibatis.type.JdbcType; import tk.mybatis.mapper.annotation.ColumnType; import javax.persistence.Id; import java.io.Serializable; /** * Description: Country * Author: liuzh * Update: liuzh(2014-06-06 13:38) */ public class Country implements Serializable { private static final long serialVersionUID = 6569081236403751407L; @Id @ColumnType(jdbcType = JdbcType.BIGINT) private Long id; private String countryname; private String countrycode; @Override public String toString() { return "Country{" + "id=" + id + ", countryname='" + countryname + '\'' + ", countrycode='" + countrycode + '\'' + '}'; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getCountryname() { return countryname; } public void setCountryname(String countryname) { this.countryname = countryname; } public String getCountrycode() { return countrycode; } public void setCountrycode(String countrycode) { this.countrycode = countrycode; } }
user-server:提供服务注册到Eureka,生产者
目录结构
pom依赖
<!-- 引入实体类 --> <dependency> <groupId>com.thomas</groupId> <artifactId>user-common</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--mapper启动器 --> <!-- https://mvnrepository.com/artifact/tk.mybatis/mapper-spring-boot-starter --> <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper-spring-boot-starter</artifactId> <version>2.1.5</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency>
application.yml 配置文件
server: port: 8081 servlet: context-path: / spring: datasource: url: jdbc:mysql://localhost:3306/frame?characterEncoding=utf-8&serverTimezone=UTC username: root password: 403411 driver-class-name: com.mysql.cj.jdbc.Driver thymeleaf: cache: false application: name: user-service mybatis: type-aliases-package: com.thomas.usercommon.model configuration: map-underscore-to-camel-case: true eureka: client: service-url: defaultZone: http://localhost:10086/eureka,http://localhost:10087/eureka instance: prefer-ip-address: true ip-address: 127.0.0.1
CountryMapper
package com.thomas.userserver.mapper; import com.thomas.usercommon.model.Country; import tk.mybatis.mapper.common.Mapper; /** * @author Thomas * @version 1.0 * @date 2019/12/25 15:12 */ @org.apache.ibatis.annotations.Mapper public interface CountryMapper extends Mapper<Country> { }
ICountryService
package com.thomas.userserver.service; import com.thomas.usercommon.model.Country; import java.util.List; /** * @author Thomas * @version 1.0 * @date 2019/12/25 15:11 */ public interface ICountryService { public List<Country> queryAll(); }
CountryServiceImpl
package com.thomas.userserver.service.Impl; import com.thomas.usercommon.model.Country; import com.thomas.userserver.mapper.CountryMapper; import com.thomas.userserver.service.ICountryService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; /** * @author Thomas * @version 1.0 * @date 2019/12/25 15:11 */ @Service public class CountryServiceImpl implements ICountryService { @Autowired private CountryMapper userMapper; @Override public List<Country> queryAll() { List<Country> countries = userMapper.selectAll(); return countries; } }
CountryController
package com.thomas.userserver.comtroller; import com.thomas.usercommon.model.Country; import com.thomas.userserver.service.ICountryService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; /** * @author Thomas * @version 1.0 * @date 2019/12/25 15:45 */ @RestController public class CountryController { @Autowired ICountryService countryService; @RequestMapping(value = "findall") public String getAll(){ List<Country> countries = countryService.queryAll(); StringBuilder sb = new StringBuilder(); for (Country country : countries) { sb.append(country).toString(); } return sb.toString(); } }
UserServerApplication:启动类
package com.thomas.userserver; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient public class UserServerApplication { public static void main(String[] args) { SpringApplication.run(UserServerApplication.class, args); } }
user-consumer:消费者
pom依赖
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
application.yml 配置文件
server: port: 8083 spring: datasource: url: jdbc:mysql://localhost:3306/frame?characterEncoding=utf-8&serverTimezone=UTC username: root password: 403411 driver-class-name: com.mysql.cj.jdbc.Driver thymeleaf: cache: false application: name: user-consumer cloud: loadbalancer: retry: enabled: true # 开启Spring Cloud的重试功能 user-service: ribbon: ConnectTimeout: 250 # Ribbon的连接超时时间 ReadTimeout: 1000 # Ribbon的数据读取超时时间 OkToRetryOnAllOperations: true # 是否对所有操作都进行重试 MaxAutoRetriesNextServer: 1 # 切换实例的重试次数 MaxAutoRetries: 1 # 对当前实例的重试次数 mybatis: type-aliases-package: com.thomas.usercommon.model configuration: map-underscore-to-camel-case: true eureka: client: service-url: defaultZone: http://localhost:10086/eureka,http://localhost:10087/eureka instance: prefer-ip-address: true ip-address: 127.0.0.1
ConsumerController
package com.thomas.userconsumer.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.context.annotation.Bean; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import java.util.List; /** * @author Thomas * @version 1.0 * @date 2019/12/25 16:05 */ @RestController public class ConsumerController { private String SERVICEURL = "http://localhost:8081/findall"; @Autowired private RestTemplate restTemplate; @Autowired private DiscoveryClient discoveryClient; @RequestMapping(value = "findall") public String getAll(){ String forObject = restTemplate.getForObject(SERVICEURL, String.class); return forObject; } @RequestMapping(value = "getAll2") public String getAll2(){ List<ServiceInstance> instances = discoveryClient.getInstances("user-service"); //instances.get(0) 获取server配置文件中defaultZone: http://localhost:10086/eureka,http://localhost:10087/eureka ServiceInstance instance = instances.get(0); String host = instance.getHost(); int port = instance.getPort(); String urlByEureka = "http://" + host + ":" + port + "/findall"; return restTemplate.getForObject(urlByEureka, String.class); } }
ConsumerController2
package com.thomas.userconsumer.controller; import com.sun.webkit.LoadListenerClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; /** * @author Thomas * @version 1.0 * @date 2019/12/25 16:50 */ @RestController public class ConsumerController2 { @Autowired private RestTemplate restTemplate; @Autowired private LoadBalancerClient loadBalancerClient; @RequestMapping(value = "getAll") public String getAll1(){ ServiceInstance choose = loadBalancerClient.choose("user-service"); String host = choose.getHost(); int port = choose.getPort(); String urlByEureka = "http://" + host + ":" + port + "/findall"; String template = restTemplate.getForObject(urlByEureka, String.class); return template; } @RequestMapping(value = "getAll3") public String getAll3(){ String template = restTemplate.getForObject("http://user-service/findall", String.class); return template; } @RequestMapping(value = "getAll4") public String getAll4(){ ResponseEntity<String> forEntity = restTemplate.getForEntity("http://user-service/findall", String.class); HttpStatus statusCode = forEntity.getStatusCode(); int statusCodeValue = forEntity.getStatusCodeValue(); HttpHeaders headers = forEntity.getHeaders(); String body = forEntity.getBody(); StringBuilder builder = new StringBuilder(); builder.append("forEntity.getStatusCode() = ").append(statusCode).append("<br>") .append("forEntity.getStatusCodeValue() = ").append(statusCodeValue).append("<br>") .append("forEntity.getHeaders() = ").append(headers).append("<br>") .append("forEntity.getBody()").append(body).append("<br>"); return builder.toString(); } }
Eureka启用HA模式
目录结构
application.yml
server: port: 10086 eureka: client: service-url: defaultZone: http://localhost:10087/eureka instance: prefer-ip-address: true ip-address: 127.0.0.1 spring: application: name: eureka-server
application-dev.yml
server: port: 10087 eureka: client: service-url: defaultZone: http://localhost:10086/eureka instance: prefer-ip-address: true ip-address: 127.0.0.1 spring: application: name: eureka-server
HA模式图
Eureka运行报错
错误一:java.lang.IllegalStateException: No instances available for 127.0.0.1
错误原因:在主加载类中使用了@LoadBalanced 负载均衡注解
1:不要使用ip+port的方式访问,取而代之的是应用名
2:这种方式发送的请求都会被ribbon拦截,ribbon从eureka注册中心获取服务列表,然后采用均衡策略进行访问
解释
错误二:java.net.UnknownHostException: user-service
原因:主加载类中没有使用@LoadBalanced 负载均衡注解