以下是本人学习的观点,如果有错或者说得不全面,记得告诉我哟
微服务
指的是微服务的大小,是一个点,针对具体解决某一个问题对应服务的一个服务应用,在idea中可以理解为一个独立的小模块,一个模块就做一件事情。这一个个小模块都可以称为微服务。
微服务架构
微服务架构相当于管理微服务的一种规范,使用各种注解和配置让服务之间能够相互协调,相互配合,为用户提供服务。
SpringCloud
基于SpringBoot提供了一套微服务解决方案,包括服务注册与发现,配置中心,全链路监控,服务网关,负载均衡,熔断器等组件。同时是分布式微服务架构下的一站式解决方案,是各个微服务架构落地技术的集合体,俗称微服务全家桶。
版本问题是SpringCloud最烦的一个东西,我这里是学习,能运行就可以了,没有采用最新的。望谅解。
SpringCloud的各组件使用
1.在idea上新建(maven项目)一个module,把统一的包先导入,再在这个module新建其他组件。
<!--打包方法 pom-->
<packaging>pom</packaging>
<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>
</properties>
<dependencyManagement>
<dependencies>
<!-- springcloud的依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- springBoot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.3.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 数据库-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.8</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
<!-- SpringBoot启动器-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</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>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5</version>
</dependency>
</dependencies>
</dependencyManagement>
2.我在这里自定义了一个api子模块,用来存放对象信息供给提供者和消费者共享
import java.io.Serializable;
public class Dept implements Serializable {//Dept实体类,orm 类表关系映射
private Long deptno;//主键
private String dname;
//这个数据是存在哪个数据库的字段~微服务,一个服务对应一个数据量,同一个信息可能存在不同的数据库
private String db_source;
public Dept(String dname) {
this.dname = dname;
}
public Dept() {
}
public Long getDeptno() {
return deptno;
}
public void setDeptno(Long deptno) {
this.deptno = deptno;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
public String getDb_source() {
return db_source;
}
public void setDb_source(String db_source) {
this.db_source = db_source;
}
@Override
public String toString() {
return "Dept{" +
"deptno=" + deptno +
", dname='" + dname + '\'' +
", db_source='" + db_source + '\'' +
'}';
}
}
Rest服务提供者
Rest风格的增删查改服务。
新建一个名为springcloud-provider-dept-8001的子目录
有些包导入了并不是这里的内容,因为组件是统一相互协调合作的,后面也会加回来,所以我也不删掉了,下面的依赖同理。
<dependencies>
<!-- hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<!-- EUREKA-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
<!--我们需要拿到实体类,所以要配置api module-->
<dependency>
<groupId>com.fever</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</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>
<!-- test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
<!-- jetty-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
</dependencies>
1.建数据库,直接建3个吧,后面会尝试多个数据库一起使用
2.编写dao数据库层,再配置mybatis,把数据搞到手
先配置application.yml,在里面配置mybatis,采用了druid数据源:
server:
port: 8001
#mybatis配置
mybatis:
type-aliases-package: com.fever.springcloud.pojo
config-location: classpath:mybatis/mybatis-config.xml
mapper-locations: classpath:mybatis/mapper/*.xml
spring:
application:
name: springcloud-provider-dept
datasource:
type: com.alibaba.druid.pool.DruidDataSource #数据源
driver-class-name: org.gjt.mm.mysql.Driver
url: jdbc:mysql://localhost:3306/springcloud1?useUnicode=true&characterEncoding=utf-8
username: root
password: 1234
在resources下新建mybatis配置文件:
mybatis-config.xml:配置mybatis
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
</configuration>
DeptMapper.xml:数据库操作语句配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.fever.springcloud.dao.DeptDao">
<insert id="addDept" parameterType="Dept">
insert into dept (dname,db_source)
VALUES (#{dname},DATABASE());
</insert>
<select id="queryById" resultType="Dept" parameterType="Long">
select * from dept where deptno = #{deptno};
</select>
<select id="queryAll" resultType="Dept">
select * from dept;
</select>
</mapper>
编写dao层:
DeptDao接口:数据库接口,会自动调用mybatis操作同时提供给service业务层调用
import com.fever.springcloud.pojo.Dept;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
@Mapper
@Repository
public interface DeptDao {
public boolean addDept(Dept dept);
public Dept queryById(Long id);
public List<Dept> queryAll();
}
写完dao层就是写service层
DeptService接口:编写业务逻辑,调用dao层的接口进行数据操作,controller层与之直接交互,就是控制层调用service业务层的接口进行展示数据。
import com.fever.springcloud.pojo.Dept;
import java.util.List;
public interface DeptService {
public boolean addDept(Dept dept);
public Dept queryById(Long id);
public List<Dept> queryAll();
}
DeptServiceImpl:接口的具体操作
import com.fever.springcloud.dao.DeptDao;
import com.fever.springcloud.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class DeptServiceImpl implements DeptService{
@Autowired
private DeptDao deptDao;
@Override
public boolean addDept(Dept dept) {
return deptDao.addDept(dept);
}
@Override
public Dept queryById(Long id) {
return deptDao.queryById(id);
}
@Override
public List<Dept> queryAll() {
return deptDao.queryAll();
}
}
接着就是controller控制层的编写
DeptController:调用业务层接口和页面直接打交道,Rest风格也在这里的url体现
import com.fever.springcloud.pojo.Dept;
import com.fever.springcloud.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.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class DeptController {
@Autowired
private DeptService deptService;
//获取一些配置的信息,得到具体的微服务!
@Autowired
private DiscoveryClient client;
@PostMapping("/dept/add")
public boolean addDept(Dept dept){
return deptService.addDept(dept);
}
@GetMapping("/dept/get/{id}")
public Dept get(@PathVariable("id") Long id){
Dept dept = deptService.queryById(id);
if (dept==null){
throw new RuntimeException("id=>"+id+",不存在该用户,或者信息无法找到~");
}
return dept;
}
@GetMapping("/dept/list")
public List<Dept> queryAll(){
return deptService.queryAll();
}
}
编写启动类DeptProvider_8001
@SpringBootApplication
public class DeptProvider_8001 {
public static void main(String[] args){
SpringApplication.run(DeptProvider_8001.class,args);
}
Rest服务消费者
消费者就是我们使用这些服务的用户
目录
pom.xml
<dependencies>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.16</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-autoconfigure -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
<dependency>
<groupId>com.fever</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>
</dependencies>
application.yml
server:
port: 81
DeptConsumerController:消费者控制类
@RestController
public class DeptConsumerController {
//理解:消费者,不应该有service层
//RestTemplate....供我们直接调用!注册到spring中
//(url,实体:Map,Class<T> responseType)
@Autowired
private RestTemplate restTemplate;//提供多种便捷访问远程http服务的方法,简单的Restful服务模板
private static final String REST_URL_PREFIX ="http://localhost:8001";
@RequestMapping("/consumer/dept/add")
public boolean add(Dept dept){
return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add",dept,Boolean.class);
}
@RequestMapping("/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id,Dept.class);
}
@RequestMapping("/consumer/dept/list")
public List<Dept> list(){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/list",List.class);
}
}
DeptConsumer_81:启动类
@SpringBootApplication
public class DeptConsumer_81 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_81.class,args);
}
}
Eureka服务注册与发现
把服务注册,并且启动发现,让用户可以使用这些服务,同时可以进行其他组件功能对这些服务进行管理和调配。访问:www.eureka7001.com:7001.
目录
pom.xml
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
</dependencies>
application.yml我这里配置了三个一样的服务
server:
port: 7001
#Eureka配置
eureka:
instance:
hostname: eureka7001.com #Eureka服务端的实例名称
client:
register-with-eureka: false #表示是否向eureka注册中心注册自己
fetch-registry: false #fetch-registry如果为false,则表示自己为注册中心
service-url:
#监控页面
#单机:http://${eureka.instance.hostname}:${server.port}/eureka/
#集群(关联):
defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
EurekaServer_7001:启动类
@SpringBootApplication
@EnableEurekaServer//服务端的启动类
public class EurekaServer_7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaServer_7001.class,args);
}
}
在服务提供者springcloud-provider-dept-8001导入包
<!-- EUREKA-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
在服务提供者springcloud-provider-dept-8001的application.yml添加
#EUREKA的配置,服务注册到哪里
eureka:
client:
service-url: #监控页面
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: springcloud-provider-dept8001 #修改eureka上的默认描述信息!
在服务提供者springcloud-provider-dept-8001的DeptController添加
//注册进来的微服务~获取一些消息~
@GetMapping("/dept/discovery")
public Object discovery(){
//获取微服务列表的清单
List<String> services=client.getServices();
System.out.println("discovery=>services:"+services);
//得到一个具体的的为服务信息,通过具体的微服务id,applicationName:
List<ServiceInstance> instances=client.getInstances("SPRINGCLOUD-PROVIDER-DEPT");
for (ServiceInstance instance : instances) {
System.out.println(
instance.getHost()+"\t"+
instance.getPort()+"\t"+
instance.getUri()+"\t"+
instance.getServiceId()
);
}
return this.client;
}
在服务提供者springcloud-provider-dept-8001的DeptProvider_8001添加
@EnableEurekaClient //在服务启动后自动注册到Eureka中
@EnableDiscoveryClient//服务发现~
在服务消费者springcloud-consumer-dept-80的pom.xml添加
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
在服务消费者springcloud-consumer-dept-80的application.yml添加
#Eureka配置
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/,http://eureka7001.com:7001/eureka/
在服务消费者springcloud-consumer-dept-80的DeptConsumer_81添加
@EnableEurekaClient
Ribbon负载均衡
让服务之间能平衡工作,不会全都挤在一个服务中,导致效率不佳。
在服务消费者springcloud-consumer-dept-80的pom.xml添加
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
在服务消费者springcloud-consumer-dept-80的FeverRandomRule添加自定义负载均衡
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
public class FeverRandomRule extends AbstractLoadBalancerRule {
//每个服务,访问5次,换下一个服务(3个)
//total=0,默认=0,如果=5,我们指向下一个服务节点
//index=0,默认0,如果total=5,index+1.
private int total=0; //被调用的次数
private int currentIndex = 0;//当前是谁在提供服务~
public FeverRandomRule() {
}
@SuppressWarnings({"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"})
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
} else {
Server server = null;
while(server == null) {
if (Thread.interrupted()) {
return null;
}
List<Server> upList = lb.getReachableServers();//获得活着的服务
List<Server> allList = lb.getAllServers();//获得全部的服务
int serverCount = allList.size();
if (serverCount == 0) {
return null;
}
int index = this.chooseRandomInt(serverCount);//生成区间随机数
server = (Server)upList.get(index);//从活着的服务中,随机获取一个
//-=============================================
if(total<5){
server = upList.get(currentIndex);
total++;
}else{
total = 0;
currentIndex++;
if(currentIndex>=upList.size()){
currentIndex=0;
}
server = upList.get(currentIndex);//从活着的服务中,获取指定的服务来进行操作
}
//-==============================================
if (server == null) {
Thread.yield();
} else {
if (server.isAlive()) {
return server;
}
server = null;
Thread.yield();
}
}
return server;
}
}
protected int chooseRandomInt(int serverCount) {
return ThreadLocalRandom.current().nextInt(serverCount);
}
public Server choose(Object key) {
return this.choose(this.getLoadBalancer(), key);
}
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
}
在服务消费者springcloud-consumer-dept-80的feverRule添加
import com.netflix.loadbalancer.IRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class feverRule {
@Bean
public IRule myRule(){
return new FeverRandomRule();//默认是轮询,现在我们定义为~FeverRandomRule
}
}
在服务消费者springcloud-consumer-dept-80的ConfigBean添加
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;
@Configuration//spring applicationContext.xml
public class ConfigBean {
//配置负载均衡实现RestTemplate
//IRule
//RoundRobinRule 轮询
//RandomRule 随机
//AvailabilityFilteringRule: 会先过滤掉,跳闸,访问故障的服务~对剩下的进行轮询!
//RetryRule : 会先按照轮询获取服务~如果服务获取失败,则会在指定的时间内进行,重试。
@Bean
@LoadBalanced//Ribbon
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
在服务消费者springcloud-consumer-dept-80的DeptConsumerController添加
//Ribbon,我们这里的地址,应该是一个变量,通过服务名来访问
//private static final String REST_URL_PREFIX ="http://localhost:8001";
private static final String REST_URL_PREFIX ="http://SPRINGCLOUD-PROVIDER-DEPT";
在服务消费者springcloud-consumer-dept-80的DeptConsumer_81添加
//在微服务启动的时候就能去加载我们自定义Ribbon类
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = feverRule.class)
Feign使用接口方式调用服务
这里新建一个消费者来使用feign,防止混淆前面的
创建springcloud-consumer-dept-feign
在服务消费者springcloud-consumer-dept-feign的pom.xml添加
<dependencies>
<!-- feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<!-- Ribbon-->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-ribbon -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.16</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-autoconfigure -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
<dependency>
<groupId>com.fever</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>
</dependencies>
在服务消费者springcloud-consumer-dept-feign的application.yml添加
# 开启降级feign.hystrix
feign:
hystrix:
enabled: true
在服务消费者springcloud-consumer-dept-feign的DeptConsumerController添加
@RestController
public class DeptConsumerController {
@Autowired
private DeptClientService service=null;
@RequestMapping("/consumer/dept/add")
public boolean add(Dept dept){
return this.service.addDept(dept);
}
@RequestMapping("/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id){
return this.service.queryById(id);
}
@RequestMapping("/consumer/dept/list")
public List<Dept> list(){
return this.service.queryAll();
}
在服务消费者springcloud-consumer-dept-feign的FeignDeptConsumer_81添加
//Ribbon 和 Eureka 整合以后,客户端可以直接调用,不用关心IP地址
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = {"com.fever.springcloud"})
public class FeignDeptConsumer_81 {
public static void main(String[] args) {
SpringApplication.run(FeignDeptConsumer_81.class,args);
}
}
Hystrix熔断器
这里新建一个提供者来使用Hystrix,防止混淆前面的
springcloud-provider-dept-hystrix-8001
在服务提供者springcloud-provider-dept-hystrix-8001的pom.xml添加
<!-- hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
在服务提供者springcloud-provider-dept-hystrix-8001的DeptController添加
import com.fever.springcloud.pojo.Dept;
import com.fever.springcloud.service.DeptService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
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;
//提供Restful服务!
@RestController
public class DeptController {
@Autowired
private DeptService deptService;
@HystrixCommand(fallbackMethod = "hystrixGet")
@GetMapping("/dept/get/{id}")
public Dept get(@PathVariable("id") Long id){
Dept dept = deptService.queryById(id);
if (dept==null){
throw new RuntimeException("id=>"+id+",不存在该用户,或者信息无法找到~");
}
return dept;
}
//备选方法
public Dept hystrixGet(@PathVariable("id") Long id){
Dept dept=new Dept();
dept.setDeptno(id);
dept.setDb_source("no this database in MySQL");
dept.setDname("id=>"+id+"没有对应的信息,null--@Hystrix");
return dept;
}
}
在服务提供者springcloud-provider-dept-hystrix-8001的DeptProviderHystrix_8001添加
import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
@EnableEurekaClient //在服务启动后自动注册到Eureka中
@EnableDiscoveryClient//服务发现~
@EnableCircuitBreaker//添加对熔断的支持
public class DeptProviderHystrix_8001 {
public static void main(String[] args){
SpringApplication.run(DeptProviderHystrix_8001.class,args);
}
//增加一个Servlet
@Bean
public ServletRegistrationBean hystrixMetricsStreamServlet(){
ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
registrationBean.addUrlMappings("/actuator/hystrix.stream");
return registrationBean;
}
}
Zuul路由网关
控制服务路由,重新声明服务id,作用是不暴露服务id和路径
application.yml
server:
port: 9501
spring:
application:
name: springcloud-zuul
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: zuul9527.com
prefer-ip-address: true
#info配置
info:
app.name: fever-springcloud
company.name: blog.feverstudy.com
zuul:
routes:
mydept.serviceId: springcloud-provider-dept
mydept.path: /mydept/**
ignored-services: "*" #不能再使用这个路径访问了,ignored:忽略
prefix: /fever #设置公共的前缀
ZuulApplication_9527
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication_9527 {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication_9527.class,args);
}
}
Config:使用Git环境搭建
1.首先搭建git仓库
https://blog.csdn.net/weixin_43906969/article/details/113788314?spm=1001.2014.3001.5502
然后把以下配置文件上传上码云项目里,以便接下来访问
** application.yml**
spring:
profiles:
active: dev
---
spring:
profiles: dev
application:
name: springcloud-config-dev
---
spring:
profiles: test
application:
name: springcloud-config-test
config-client.yml:
spring:
profiles:
active: dev
---
server:
port: 8201
#spring的配置
spring:
profiles: dev
application:
name: springcloud-provider-dept
#EUREKA的配置,服务注册到哪里
eureka:
client:
service-url: #监控页面
defaultZone: http://eureka7001.com:7001/eureka/
---
server:
port: 8202
#spring的配置
spring:
profiles: test
application:
name: springcloud-provider-dept
#EUREKA的配置,服务注册到哪里
eureka:
client:
service-url: #监控页面
defaultZone: http://eureka7001.com:7001/eureka/
config-dept.yml
spring:
profiles:
active: dev
---
server:
port: 8001
#mybatis配置
mybatis:
type-aliases-package: com.fever.springcloud.pojo
config-location: classpath:mybatis/mybatis-config.xml
mapper-locations: classpath:mybatis/mapper/*.xml
spring:
profiles: dev
application:
name: springcloud-config-dept
datasource:
type: com.alibaba.druid.pool.DruidDataSource #数据源
driver-class-name: org.gjt.mm.mysql.Driver
url: jdbc:mysql://localhost:3306/springcloud1?useUnicode=true&characterEncoding=utf-8
username: root
password: 1234
#EUREKA的配置,服务注册到哪里
eureka:
client:
service-url: #监控页面
defaultZone: http://eureka7001.com:7001/eureka/
instance:
instance-id: springcloud-provider-dept8001 #修改eureka上的默认描述信息!
#info配置
info:
app.name: fever-springcloud
company.name: blog.feverstudy.com
---
server:
port: 8001
#mybatis配置
mybatis:
type-aliases-package: com.fever.springcloud.pojo
config-location: classpath:mybatis/mybatis-config.xml
mapper-locations: classpath:mybatis/mapper/*.xml
spring:
profiles: test
application:
name: springcloud-config-dept
datasource:
type: com.alibaba.druid.pool.DruidDataSource #数据源
driver-class-name: org.gjt.mm.mysql.Driver
url: jdbc:mysql://localhost:3306/springcloud3?useUnicode=true&characterEncoding=utf-8
username: root
password: 1234
#EUREKA的配置,服务注册到哪里
eureka:
client:
service-url: #监控页面
defaultZone: http://eureka7001.com:7001/eureka/
instance:
instance-id: springcloud-provider-dept8001 #修改eureka上的默认描述信息!
#info配置
info:
app.name: fever-springcloud
company.name: blog.feverstudy.com
config-eureka.yml
spring:
profiles:
active: dev
---
server:
port: 7001
#spring的配置
spring:
profiles: dev
application:
name: springcloud-config-eureka
#Eureka配置
eureka:
instance:
hostname: eureka7001.com #Eureka服务端的实例名称
client:
register-with-eureka: false #表示是否向eureka注册中心注册自己
fetch-registry: false #fetch-registry如果为false,则表示自己为注册中心
service-url:
#监控页面
#单机:http://${eureka.instance.hostname}:${server.port}/eureka/
#集群(关联):
defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
---
server:
port: 7001
#spring的配置
spring:
profiles: test
application:
name: springcloud-config-eureka
#Eureka配置
eureka:
instance:
hostname: eureka7001.com #Eureka服务端的实例名称
client:
register-with-eureka: false #表示是否向eureka注册中心注册自己
fetch-registry: false #fetch-registry如果为false,则表示自己为注册中心
service-url:
#监控页面
#单机:http://${eureka.instance.hostname}:${server.port}/eureka/
#集群(关联):
defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
自定义了一个api子模块,用来存放对象信息供给提供者和消费者共享
import java.io.Serializable;
public class Dept implements Serializable {//Dept实体类,orm 类表关系映射
private Long deptno;//主键
private String dname;
//这个数据是存在哪个数据库的字段~微服务,一个服务对应一个数据量,同一个信息可能存在不同的数据库
private String db_source;
public Dept(String dname) {
this.dname = dname;
}
public Dept() {
}
public Long getDeptno() {
return deptno;
}
public void setDeptno(Long deptno) {
this.deptno = deptno;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
public String getDb_source() {
return db_source;
}
public void setDb_source(String db_source) {
this.db_source = db_source;
}
@Override
public String toString() {
return "Dept{" +
"deptno=" + deptno +
", dname='" + dname + '\'' +
", db_source='" + db_source + '\'' +
'}';
}
}
idea项目连接git仓库:用来连接git,获取配置文件
springcloud-config-server-3344的pom.xml:
<dependencies>
<!-- config-->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-config-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
</dependencies>
springcloud-config-server-3344的application.yml:
server:
port: 3344
spring:
application:
name: springcloud-config-server
#连接远程仓库
cloud:
config:
server:
git:
uri: https://gitee.com/fever888/springcloud-config.git #https,不是git
springcloud-config-server-3344的Config_Server_3344:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
@SpringBootApplication
@EnableConfigServer
public class Config_Server_3344 {
public static void main(String[] args) {
SpringApplication.run(Config_Server_3344.class,args);
}
}
服务提供者springcloud-config-dept-8001
目录
服务提供者springcloud-config-dept-8001的pom.xml
<dependencies>
<!-- config-->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-config-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
<!-- hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<!-- EUREKA-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
<!--我们需要拿到实体类,所以要配置api module-->
<dependency>
<groupId>com.fever</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</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>
<!-- test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
<!-- jetty-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
</dependencies>
服务提供者springcloud-config-dept-8001的application.yml
spring:
application:
name: springcloud-config-dept-8001
服务提供者springcloud-config-dept-8001的bootstrap.yml
spring:
cloud:
config:
name: config-dept
label: master
profile: test
uri: http://localhost:3344
服务提供者springcloud-config-dept-8001的DeptDao
@Mapper
@Repository
public interface DeptDao {
public boolean addDept(Dept dept);
public Dept queryById(Long id);
public List<Dept> queryAll();
}
服务提供者springcloud-config-dept-8001的mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
</configuration>
服务提供者springcloud-config-dept-8001的DeptMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.fever.springcloud.dao.DeptDao">
<insert id="addDept" parameterType="Dept">
insert into dept (dname,db_source)
VALUES (#{dname},DATABASE());
</insert>
<select id="queryById" resultType="Dept" parameterType="Long">
select * from dept where deptno = #{deptno};
</select>
<select id="queryAll" resultType="Dept">
select * from dept;
</select>
</mapper>
服务提供者springcloud-config-dept-8001的DeptService
public interface DeptService {
public boolean addDept(Dept dept);
public Dept queryById(Long id);
public List<Dept> queryAll();
}
服务提供者springcloud-config-dept-8001的DeptServiceImpl
@Service
public class DeptServiceImpl implements DeptService{
@Autowired
private DeptDao deptDao;
@Override
public boolean addDept(Dept dept) {
return deptDao.addDept(dept);
}
@Override
public Dept queryById(Long id) {
return deptDao.queryById(id);
}
@Override
public List<Dept> queryAll() {
return deptDao.queryAll();
}
}
服务提供者springcloud-config-dept-8001的DeptController
import com.fever.springcloud.pojo.Dept;
import com.fever.springcloud.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.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class DeptController {
@Autowired
private DeptService deptService;
//获取一些配置的信息,得到具体的微服务!
@Autowired
private DiscoveryClient client;
@PostMapping("/dept/add")
public boolean addDept(Dept dept){
return deptService.addDept(dept);
}
@GetMapping("/dept/get/{id}")
public Dept get(@PathVariable("id") Long id){
Dept dept = deptService.queryById(id);
if (dept==null){
throw new RuntimeException("id=>"+id+",不存在该用户,或者信息无法找到~");
}
return dept;
}
@GetMapping("/dept/list")
public List<Dept> queryAll(){
return deptService.queryAll();
}
//注册进来的微服务~获取一些消息~
@GetMapping("/dept/discovery")
public Object discovery(){
//获取微服务列表的清单
List<String> services=client.getServices();
System.out.println("discovery=>services:"+services);
//得到一个具体的的为服务信息,通过具体的微服务id,applicationName:
List<ServiceInstance> instances=client.getInstances("SPRINGCLOUD-PROVIDER-DEPT");
for (ServiceInstance instance : instances) {
System.out.println(
instance.getHost()+"\t"+
instance.getPort()+"\t"+
instance.getUri()+"\t"+
instance.getServiceId()
);
}
return this.client;
}
}
服务提供者springcloud-config-dept-8001的DeptProvider_8001
@SpringBootApplication
@EnableEurekaClient //在服务启动后自动注册到Eureka中
@EnableDiscoveryClient//服务发现~
public class DeptProvider_8001 {
public static void main(String[] args){
SpringApplication.run(DeptProvider_8001.class,args);
}
}
注册与发现服务springcloud-config-eureka-7001
注册与发现服务springcloud-config-eureka-7001的pom.xml
<dependencies>
<!-- config-->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-config-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
</dependencies>
注册与发现服务springcloud-config-eureka-7001的application.yml
spring:
application:
name: springcloud-config-eureka-7001
注册与发现服务springcloud-config-eureka-7001的bootstrap.yml
spring:
cloud:
config:
name: config-eureka
label: master
profile: dev
uri: http://localhost:3344
注册与发现服务springcloud-config-eureka-7001的EurekaServer_7001
@SpringBootApplication
@EnableEurekaServer//服务端的启动类
public class EurekaServer_7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaServer_7001.class,args);
}
}
服务消费者springcloud-config-client-3355
服务消费者springcloud-config-client-3355的pom.xml
<dependencies>
<!-- config-->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-config-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
</dependencies>
服务消费者springcloud-config-client-3355的application.yml
#用户级别的配置spring
spring:
application:
name: springcloud-config-client-3355
服务消费者springcloud-config-client-3355的bootstrap.yml
#用户级别的配置spring
spring:
application:
name: springcloud-config-client-3355
服务消费者springcloud-config-client-3355的ConfigClientController
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConfigClientController {
@Value("${spring.application.name}")
private String applicationName;
@Value("${eureka.client.service-url.defaultZone}")
private String eurekaServer;
@Value("${server.port}")
private String port;
@RequestMapping("/config")
public String getConfig(){
return "applicationName:"+applicationName+
"<br/>"+"eurekaServer:"+eurekaServer+
"<br/>"+"port:"+port;
}
}
服务消费者springcloud-config-client-3355的ConfigClient_3355
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ConfigClient_3355 {
public static void main(String[] args) {
SpringApplication.run(ConfigClient_3355.class,args);
}
}
然后全部config打开就可以直接访问消费者或者提供者服务了