springCloud基础搭建

SpringCloud简单介绍及基础搭建

springcloud介绍

Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智能路由,微代理,控制总线)。分布式系统的协调导致了样板模式, 使用Spring Cloud开发人员可以快速地支持实现这些模式的服务和应用程序。他们将在任何分布式环境中运行良好,包括开发人员自己的笔记本电脑,裸机数据中心,以及Cloud Foundry等托管平台。

Spring Cloud中文网-链接: [link]https://springcloud.cc/

1、创建parent项目

  • 设置一个workSet,并在其下面新建maven工程,Gid为com.sc.springcloud,Aid为microservicecloud,由于是父工程,所以选择pom,然后finish

填写主项目(microservicecloud)pom.xml
在这里插入图片描述
主项目(microservicecloud)pom.xml

<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.sc.springcloud</groupId>
	<artifactId>microservicecloud</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<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>
		<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>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>

	<build>
		<finalName>microservicecloud</finalName>
		<resources>
			<resource>
				<directory>src/main/resources</directory>
				<filtering>true</filtering>
			</resource>
		</resources>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-resources-plugin</artifactId>
				<configuration>
					<delimiters>
						<delimit>$</delimit>
					</delimiters>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>


2、创建子模块,在parent项目上新建maven子模块microservicecloud-api

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

填写子项目(microservicecloud-api)pom.xml

<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>
	<parent><!-- 子类里面显示声明才能有明确的继承表现,无意外就是父类的默认版本否则自己定义 -->
		<groupId>com.sc.springcloud</groupId>
		<artifactId>microservicecloud</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</parent>
	<artifactId>microservicecloud-api</artifactId><!-- 当前Module我自己叫什么名字 -->

	<dependencies><!-- 当前Module需要用到的jar包,按自己需求添加,如果父类已经包含了,可以不用写版本号 -->
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-feign</artifactId>
		</dependency>
	</dependencies>
</project>

2.1、在microservicecloud-api项目新建entity

  • 注意,一定要实现序列化接口implements Serializable#
  • 利用注释可以省去get、set和构造方法
    @Data
    @NoArgsConstructor
    需要引入了lombok包#
package com.sc.springcloud.entities;

import java.io.Serializable;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

@SuppressWarnings("serial")
@NoArgsConstructor
// @AllArgsConstructor
@Data
@Accessors(chain = true) // 链式风格访问
public class Dept implements Serializable// entity --orm--- db_table
{
	private Long deptno; // 主键
	private String dname; // 部门名称
	private String db_source;// 来自那个数据库

	public Dept(String dname) {
		super();
		this.dname = dname;
	}

	public static void main(String[] args) {
		Dept dept = new Dept();
		/* @Accessors(chain=true)链式风格 */
		dept.setDeptno(11L).setDb_source("DB01");
	}
}

在这里插入图片描述
在这里插入图片描述

3、创建子模块microservicecloud-provider-dept-8001

填写pom.xml

<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>
  <parent>
    <groupId>com.sc.springcloud</groupId>
    <artifactId>microservicecloud</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <artifactId>microservicecloud-provider-dept-8001</artifactId>
  
  <dependencies>
		<!-- 引入自己定义的api通用包,可以使用Dept部门Entity -->
		<dependency>
			<groupId>com.sc.springcloud</groupId>
			<artifactId>microservicecloud-api</artifactId>
			<version>${project.version}</version>
		</dependency>
		<!-- actuator监控信息完善 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		<!-- 将微服务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>
		<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>

3.1、在资源路径下添加配置文件application.yml

#包括mybatis配置、数据库配置等#

application.yml

server:
  port: 8001                                                #相当于索引,找到8001
  
mybatis:
  config-location: classpath:mybatis/mybatis.cfg.xml        # mybatis配置文件所在路径
  type-aliases-package: com.sc.springcloud.entities    # 所有Entity别名类所在包
  mapper-locations:
  - classpath:mybatis/mapper/**/*.xml                       # mapper映射文件
    
spring:
   application:
    name: microservicecloud-dept 
   datasource:
    type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
    driver-class-name: org.gjt.mm.mysql.Driver              # mysql驱动包
    url: jdbc:mysql://localhost:3306/cloudDB01              # 数据库名称
    username: root
    password: 
    dbcp2:
      min-idle: 5                                           # 数据库连接池的最小维持连接数
      initial-size: 5                                       # 初始化连接数
      max-total: 5                                          # 最大连接数
      max-wait-millis: 200                                  # 等待连接获取的最大超时时间
      
eureka:
  client: #客户端注册进eureka服务列表内
    service-url: 
      #defaultZone: http://localhost:7001/eureka
       defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/      
  instance:
    instance-id: microservicecloud-dept8001
    prefer-ip-address: true     #访问路径可以显示IP地址     
 
info: 
  app.name: sc-microservicecloud
  company.name: www.sc.com
  build.artifactId: $project.artifactId$
  build.version: $project.version$

mybatis.cfg.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>

在这里插入图片描述
图片这段在Eureka很重要

3.2、创建dao,实现增删改

a、创建mapper映射文件DeptMapper.xml

DeptDao

package com.sc.springcloud.dao;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import com.sc.springcloud.entities.Dept;
@Mapper
public interface DeptDao
{
	public boolean addDept(Dept dept);
	public Dept findById(Long id);
	public List<Dept> findAll();
}

```xml
DeptMapper.xml

<?xml version="1.0" encoding="UTF-8" ?> select deptno,dname,db_source from dept where deptno=#{deptno}; select deptno,dname,db_source from dept; INSERT INTO dept(dname,db_source) VALUES(#{dname},DATABASE()); ```

3.3创建 DeptService、DeptServiceImpl 、DeptController

DeptService

package com.sc.springcloud.service;
import java.util.List;
import com.sc.springcloud.entities.Dept;
public interface DeptService{
	public boolean add(Dept dept);
	public Dept get(Long id);
	public List<Dept> list();
}

DeptServiceImpl

package com.sc.springcloud.service.impl;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.sc.springcloud.dao.DeptDao;
import com.atguigu.springcloud.entities.Dept;
import com.sc.springcloud.service.DeptService;

@Service
public class DeptServiceImpl implements DeptService {
	@Autowired
	private DeptDao dao;

	@Override
	public boolean add(Dept dept) {
		return dao.addDept(dept);
	}

	@Override
	public Dept get(Long id) {
		return dao.findById(id);
	}

	@Override
	public List<Dept> list() {
		return dao.findAll();
	}
}

DeptController

package com.sc.springcloud.controller;

import java.util.List;

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.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.sc.springcloud.entities.Dept;
import com.sc.springcloud.service.DeptService;

@RestController
public class DeptController {
	@Autowired
	private DeptService service;
	@Autowired
	private DiscoveryClient client;

	@RequestMapping(value = "/dept/add", method = RequestMethod.POST)
	public boolean add(@RequestBody Dept dept) {
		return service.add(dept);
	}

	@RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
	public Dept get(@PathVariable("id") Long id) {
		return service.get(id);
	}

	@RequestMapping(value = "/dept/list", method = RequestMethod.GET)
	public List<Dept> list() {
		return service.list();
	}

	// @Autowired
	// private DiscoveryClient client;
	@RequestMapping(value = "/dept/discovery", method = RequestMethod.GET)
	public Object discovery() {
		List<String> list = client.getServices();
		System.out.println("**********" + list);

		List<ServiceInstance> srvList = client.getInstances("MICROSERVICECLOUD-DEPT");
		for (ServiceInstance element : srvList) {
			System.out.println(element.getServiceId() + "\t" + element.getHost() + "\t" + element.getPort() + "\t"
					+ element.getUri());
		}
		return this.client;
	}

}

3.4、创建DeptProvider8001_Config_App启动项目

package com.sc.springcloud;

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 DeptProvider8001_Config_App{
	public static void main(String[] args)
	{
		SpringApplication.run(DeptProvider8001_Config_App.class, args);
	}
}

run as —》spring boot app(能正常访问)
在这里插入图片描述
当看到Started in多少seconds就证明启动完成
如果启动失败,把Eureka和服务注册注释掉就可以了

访问:localhost:8001/dept/list
在这里插入图片描述
sql

DROP DATABASE IF EXISTS cloudDB01;
CREATE DATABASE cloudDB01 CHARACTER SET UTF8;
USE cloudDB01;

CREATE TABLE dept
(
	deptno BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
	dname VARCHAR(60),
	db_source VARCHAR(60)
);

INSERT INTO dept(dname,db_source) VALUES ('开发部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES ('人事部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES ('财务部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES ('市场部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES ('运维部',DATABASE());

SELECT * FROM dept;

DROP DATABASE IF EXISTS cloudDB02;
CREATE DATABASE cloudDB02 CHARACTER SET UTF8;
USE cloudDB02;

CREATE TABLE dept
(
	deptno BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
	dname VARCHAR(60),
	db_source VARCHAR(60)
);

INSERT INTO dept(dname,db_source) VALUES ('开发部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES ('人事部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES ('财务部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES ('市场部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES ('运维部',DATABASE());

SELECT * FROM dept;


DROP DATABASE IF EXISTS cloudDB03;
CREATE DATABASE cloudDB03 CHARACTER SET UTF8;
USE cloudDB03;

CREATE TABLE dept
(
	deptno BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
	dname VARCHAR(60),
	db_source VARCHAR(60)
);

INSERT INTO dept(dname,db_source) VALUES ('开发部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES ('人事部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES ('财务部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES ('市场部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES ('运维部',DATABASE());

SELECT * FROM dept;

4、创建消费者模块(microservicecloud-consumer-dept-80)

编写pom.xml

<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>

	<parent>
		<groupId>com.sc.springcloud</groupId>
		<artifactId>microservicecloud</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</parent>

	<artifactId>microservicecloud-consumer-dept-80</artifactId>
	<description>部门微服务消费者</description>

	<dependencies>
		<dependency><!-- 自己定义的api -->
			<groupId>com.sc.springcloud</groupId>
			<artifactId>microservicecloud-api</artifactId>
			<version>${project.version}</version>
		</dependency>
		<!-- Ribbon相关 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-eureka</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-ribbon</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-config</artifactId>
		</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>
	</dependencies>
</project>

4.1、创建yml文件

appcation.yml

server:
  port: 80
  
eureka:
  client:
    register-with-eureka: false
    service-url: 
      defaultZone: http://eureka7001.com:7001/eureka/#,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/  

4.2、创建bean:

ConfigBean

package com.sc.springcloud.cfgbeans;

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;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import com.netflix.loadbalancer.RetryRule;
import com.netflix.loadbalancer.RoundRobinRule;

@Configuration
public class ConfigBean{ // boot -->spring applicationContext.xml ---// @Configuration配置 ConfigBean = applicationContext.xml

//	@Bean
//	@LoadBalanced // Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端 负载均衡的工具。
//	public RestTemplate getRestTemplate() {
//		return new RestTemplate();
//	}

	@Bean
	@LoadBalanced
	public RestTemplate getRestTemplate() {
		return new RestTemplate();
	}

//	@Bean
//	public IRule myRule() {
//		// return new RoundRobinRule();
//		// return new RandomRule();//达到的目的,用我们重新选择的随机算法替代默认的轮询。
//		return new RetryRule();
//	}

	@Bean
	public IRule myRule() {
		// return new RoundRobinRule();
		// return new RandomRule();
		return new RetryRule();
	}

}

//	 @Bean
//	 public UserServcie getUserServcie(){
//		 return new UserServcieImpl();
//	 }
//	 applicationContext.xml == ConfigBean(@Configuration)
//	 <bean id="userServcie" class="com.atguigu.tmall.UserServiceImpl">

DeptController_Consumer

package com.sc.springcloud.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import com.sc.springcloud.entities.Dept;

@RestController
public class DeptController_Consumer {

	// private static final String REST_URL_PREFIX = "http://localhost:8001";
	private static final String REST_URL_PREFIX = "http://MICROSERVICECLOUD-DEPT";

	/**
	 * 使用 使用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/{id}")
	public Dept get(@PathVariable("id") Long id) {
		return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, 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);
	}

}

RestTemplate 提供了多种便捷访问远程http服务的方法,是一种简单便捷的访问restful服务模版类,是Spring提供的用于访问Rest服务的客户端模版工具集

package com.sc.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;

//import com.sc.myrule.MySelfRule;

@SpringBootApplication
@EnableEurekaClient
// 在启动该微服务的时候就能去加载我们的自定义Ribbon配置类,从而使配置生效
// @RibbonClient(name="MICROSERVICECLOUD-DEPT",configuration=MySelfRule.class)
// @RibbonClient(name="MICROSERVICECLOUD-DEPT",configuration=MySelfRule.class)
public class DeptConsumer80_App {
	public static void main(String[] args) {
		SpringApplication.run(DeptConsumer80_App.class, args);
	}
}

启动项目
*如果启动失败就把Eureka注释掉
同时,把@LoadBalanced注释掉(@LoadBalanced是设置负载均衡的)

访问:localhost/consumer/dept/list

在这里插入图片描述

成功访问!

5、Eureka

  • 什么是Eureka?
    Netflix公司在设计Eureka时遵守的是AP原则
    Eureka是Netflix的一个子模块,也是核心模块之一。Eureka是一个基于rest的服务,用于定位服务,以实现云端中间层服务发现和故障转移。服务注册与发现对于微服务架构来说非常重要的,有了服务发现与注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了。功能类似于dubbo的注册中心,比如Zookeeper。

在这里插入图片描述

5.1创建microservicecloud-eureka-7001模块

填写pom.xml

<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>

	<parent>
		<groupId>com.sc.springcloud</groupId>
		<artifactId>microservicecloud</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</parent>

	<artifactId>microservicecloud-eureka-7001</artifactId>

	<dependencies>
		<!--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>
</project>

application.yml

server: 
  port: 7001
 
eureka: 
  instance:
    hostname: eureka7001.com #eureka服务端的实例名称
  client: 
    register-with-eureka: false     #false表示不向注册中心注册自己。
    fetch-registry: false     #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    service-url: 
      #单机 
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/       #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址(单机)。
      #集群
      #defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

暂时先把hostname改为localhost

创建EurekaServer7001_App

package com.sc.springcloud;

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);
	}
}

启动项目
在这里插入图片描述

访问:localhost:7001正常

在这里插入图片描述

6、把8001注册到Eureka中心

  • 修改8001的yml文件
    #将defaultZone改为http://localhost:7001/eureka
    为什么要修改为上述地址,由于7001项目里面规定了地址
    在这里插入图片描述

  • 启动8001后刷新Eureka页面会发现8001注册到上面了
    在这里插入图片描述

  • 细节:
    修改8001的yml文件,增加参数可以显示当前机器的ip地址
    在这里插入图片描述

  • 添加spring-boot-starter-actuator坐标,可以使红框出访问后显示8001的信息
    在这里插入图片描述

EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.

在自我保护模式中,Eureka Server会保护服务注册表中的信息,不再注销任何服务实例。当它收到的心跳数重新恢复到阈值以上时,该Eureka Server节点就会自动退出自我保护模式。它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。一句话讲解:好死不如赖活着。

  • 综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的都保留),也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。
    在springcloud中,可以使用eureka.server.enable-self-preservation = false禁用自我保护模式。

7、服务发现

访问:http://localhost:8001/dept/discovery
在这里插入图片描述

8、搭建Eureka集群

  • 创建microservicecloud-eureka-7002、microservicecloud-eureka-7003
    按照7001的pom.xml填写,并创建主启动类EurekaServer7002_App、EurekaServer7003_App、application.yml

  • 修改host文件(C:\Windows\System32\drivers\etc\hosts)
    添加以下配置
    127.0.0.1 eureka7001.com
    127.0.0.1 eureka7002.com
    127.0.0.1 eureka7003.com

在这里插入图片描述

8.1、修改application.yml

在这里插入图片描述

8.2修改8001项目配置

在这里插入图片描述

8.3、启动7001、7002、7003、8001

  • 访问eureka7001.com:7001eureka7002.com:7002eureka7003.com:7003
    在这里插入图片描述

  • 在Eureka平台中,如果某台服务器宕机,Eureka不会有类似于ZooKeeper的选举leader的过程;客户端请求会自动切换到新的Eureka节点;当宕机的服务器重新恢复后,Eureka会再次将其纳入到服务器集群管理之中;

9、Ribbon负载均衡

9.1、Ribbon是什么?
   Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随即连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。

9.2修改consumer为微服务调用

  • 首先不再访问8001,改为访问MICROSERVICECLOUD-DEPT
    在这里插入图片描述
  • 另外,添加ribbon注解(@LoadBalanced)实现负载均衡,不然访问不了
    在这里插入图片描述

然后访问http://localhost/consumer/dept/list,成功!
在这里插入图片描述

9.3、实现ribbon的负载均衡(根据算法实现)

  • 添加microservicecloud-provider-dept-8002、microservicecloud-provider-dept-8003子模块,并复制粘贴8001项目的类和配置文件(记得修改为8002和8003)

启动项目并访问http://localhost:8001/dept/list、http://localhost:8002/dept/list、http://localhost:8003/dept/list

可以看到已经实现了访问不同的数据库
在这里插入图片描述

此时,访问http://localhost/consumer/dept/get/1就会发现轮询访问1、2、3号库了
http://localhost/consumer/dept/get/1

9.4、自定义负载均衡

  • 实现IRule接口,可自定义算法

同时,ribbon提供了几个算法
RandomRule表示随机策略、RoundRobin表示轮询策略、WeightedResponseTimeRule表示加权策略、BestAvailableRule表示请求数最少策略等等
RetryRule //在RoundRobin策略下,具备重试机制的实例选择功能

可在此git路径下查看源码
https://github.com/Netflix/ribbon/blob/master/ribbon-loadbalancer/src/main/java/com/netflix/loadbalancer

  • 修改com.sc.springcloud.cfgbeans.ConfigBean.myRule()实现随机算法
    在这里插入图片描述
  • 如果选择RoundRobinRule算法,这个时候停了8002,会在访问几次之后不自动跳过8002,只访问8001和8003
    在这里插入图片描述
  • 以上介绍了ribbon提供的算法,下面我们开始自定义的算法
    首先创建MyDefineRule.java
package com.sc.myrule;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import com.netflix.loadbalancer.RoundRobinRule;

@Configuration
public class MyDefineRule {
	@Bean
	public IRule myRule() {
		return new RandomRule();// 随机

		// return new RebuildRandomRule();// 我自定义为每台机器3次
	}
}

注意,这个MyDefineRule不能放到负载均衡类的包或其子包下面
可参考http://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-ribbon.html
中6.2 Customizing the Ribbon Client说明

仿照RandomRule源码,编写自定义RebuildRandomRule 算法类

package com.sc.myrule;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;

public class RebuildRandomRule extends AbstractLoadBalancerRule{
	
	private int total = 0; // 总共被调用的次数,目前要求每台被调用3次
	private int currentIndex = 0; // 当前提供服务的机器号
	public Server choose(ILoadBalancer lb, Object key) {
		if (lb == null) {
			return null;
		}
		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;
			}
			if(total < 3){
				server = upList.get(currentIndex);
				total++;
			}else{
				total = 0;
				currentIndex++;
				if(currentIndex >= serverCount){//目前有3个provider,所以总数是3;
					currentIndex = 0;
				}
			}
			if (server == null) {
				Thread.yield();
				continue;
			}
			if (server.isAlive()) {
				return (server);
			}
			server = null;
			Thread.yield();
		}
		return server;
	}

	@Override
	public Server choose(Object key) {
		return choose(getLoadBalancer(), key);
	}

	@Override
	public void initWithNiwsConfig(IClientConfig arg0) {
		// TODO Auto-generated method stub
		
	}
}

10、Feign声明式服务调用

Spring Cloud Feign是基于Netflix feign实现,整合了Spring Cloud Ribbon和Spring Cloud Hystrix,除了提供这两者的强大功能外,还提供了一种声明式的Web服务客户端定义的方式。

10.1、创建Feign子模块

  • 拷贝microservicecloud-consumer-dept-80模块的java类,配置和pom,并添加Feign依赖
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
  • 创建DeptConsumer80_Feign_App 启动类
package com.sc.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = { "com.atguigu.springcloud" })
@ComponentScan("com.atguigu.springcloud")
public class DeptConsumer80_Feign_App {
	public static void main(String[] args) {
		SpringApplication.run(DeptConsumer80_Feign_App.class, args);
	}
}

10.2、microservicecloud-api下创建DeptClientService

package com.sc.springcloud.service;
import java.util.List;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.sc.springcloud.entities.Dept;
 @FeignClient(value = "MICROSERVICECLOUD-DEPT")
//@FeignClient(value = "MICROSERVICECLOUD-DEPT", fallbackFactory = DeptClientServiceFallbackFactory.class)
public interface DeptClientService {
	@RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
	public Dept get(@PathVariable("id") long id);

	@RequestMapping(value = "/dept/list", method = RequestMethod.GET)
	public List<Dept> list();

	@RequestMapping(value = "/dept/add", method = RequestMethod.POST)
	public boolean add(Dept dept);
}

10.3、修改microservicecloud-consumer-dept-feign下的DeptController_Consumer,不再使用RestTemplate

package com.sc.springcloud.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.sc.springcloud.entities.Dept;
import com.sc.springcloud.service.DeptClientService;

@RestController
public class DeptController_Consumer {
	@Autowired
	private DeptClientService service;

	@RequestMapping(value = "/consumer/dept/get/{id}")
	public Dept get(@PathVariable("id") Long id) {
		return this.service.get(id);
	}
	@RequestMapping(value = "/consumer/dept/list")
	public List<Dept> list() {
		return this.service.list();
	}
	@RequestMapping(value = "/consumer/dept/add")
	public Object add(Dept dept) {
		return this.service.add(dept);
	}
}

总结,从@FeignClient可以看出,Feign是面向服务编程,而RestTemplate则面向接口编程

11、Hystrix 断路器

  • 熔断机制
    所谓熔断机制就相当于生活中的电路保险丝,当出现问题后,保险丝会自动烧断,起到保护电器的作用。所以熔断机制就是保护服务调用,避免故障蔓延。

11.1、创建microservicecloud-provider-dept-hystrix-8001子模块

编写pom文件,参考microservicecloud-provider-dept-8001
在microservicecloud-provider-dept-8001的pom文件基础上添加hystrix坐标

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>

a、拷贝microservicecloud-provider-dept-8001的java类,和配置文件
创建启动类DeptProvider8001_Hystrix_App

package com.sc.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient // 本服务启动后会自动注册进eureka服务中
@EnableDiscoveryClient // 服务发现
@EnableCircuitBreaker // 对hystrixR熔断机制的支持
public class DeptProvider8001_Hystrix_App {
	public static void main(String[] args) {
		SpringApplication.run(DeptProvider8001_Hystrix_App.class, args);
	}
}

  • 修改application.yml中的instance-id为以下内容:
    instance-id: microservicecloud-dept8001-hystrix #自定义hystrix相关的服务名称信息

  • 修改DeptController

package com.sc.springcloud.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.sc.springcloud.entities.Dept;
import com.sc.springcloud.service.DeptService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;

@RestController
public class DeptController {
	@Autowired
	private DeptService service = null;

	@RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
	@HystrixCommand(fallbackMethod = "processHystrix_Get")
	public Dept get(@PathVariable("id") Long id) {

		Dept dept = this.service.get(id);

		if (null == dept) {
			throw new RuntimeException("该ID:" + id + "没有没有对应的信息");
		}

		return dept;
	}

	public Dept processHystrix_Get(@PathVariable("id") Long id) {
		return new Dept().setDeptno(id).setDname("此ID:" + id + "没有查询到对应信息");
	}
}
  • @HystrixCommand,一旦调用服务方法失败并抛出了错误信息后,会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法

启动eureka、provider_hystrix、consumer_feign等
访问以下两个地址,会出现以下情况,证明熔断机制实现
http://localhost/consumer/dept/get/1
在这里插入图片描述

http://localhost/consumer/dept/get/12
此时数据库没有11这条数据
在这里插入图片描述

11.2、实现hystrix松耦合

  • 创建DeptClientServiceFallbackFactory类实现FallbackFactory接口
package com.sc.springcloud.service;

import java.util.List;
import org.springframework.stereotype.Component;
import com.sc.springcloud.entities.Dept;
import feign.hystrix.FallbackFactory;

@Component
public class DeptClientServiceFallbackFactory implements FallbackFactory<DeptClientService> {
	@Override
	public DeptClientService create(Throwable throwable) {
		return new DeptClientService() {
			@Override
			public Dept get(long id) {
				return new Dept().setDeptno(id).setDname("此ID:" + id + "没有查到相关信息")
						.setDb_source("没有数据库信息");
			}
			@Override
			public List<Dept> list() {
				return null;
			}
			@Override
			public boolean add(Dept dept) {
				return false;
			}
		};
	}
}

b、修改DeptClientService中@FeignClient:
@FeignClient(value = “MICROSERVICECLOUD-DEPT”, fallbackFactory = DeptClientServiceFallbackFactory.class)

c、将DeptController中的@HystrixCommand注释掉
//@HystrixCommand(fallbackMethod = “processHystrix_Get”)

d、在microservicecloud-consumer-dept-feign的配置文件添加

feign: 
  hystrix: 
    enabled: true

重启项目,并访问consumer接口,可以得到
http://localhost/consumer/dept/get/11
在这里插入图片描述

12、Hystrix DashBoard监控面板

Hystrix Dashboard是Hystrix的一个组件,Hystrix Dashboard提供一个断路器的监控面板,可以使我们更好的监控服务和集群的状态,仅仅使用Hystrix Dashboard只能监控到单个断路器的状态,实际开发中还需要结合Turbine使用(在此我们不演示结合Turbine)

12.1、创建microservicecloud-consumer-hystrix-dashboard子模块

  • 编写pom文件(拷贝microservicecloud-consumer-dept-feign的依赖)
    再添加如下DashBoard依赖
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-hystrix</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
		</dependency>
  • 添加application.yml
server:
  port: 9001
  • 添加主启动类DeptConsumer_DashBoard_App
package com.sc.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;

@SpringBootApplication
@EnableHystrixDashboard
public class DeptConsumer_DashBoard_App {
	public static void main(String[] args) {
		SpringApplication.run(DeptConsumer_DashBoard_App.class, args);
	}
}

启动项目,访问http://localhost:9001/hystrix,看到如下网页,则成功。
在这里插入图片描述
这时候我们访问http://localhost:8001/hystrix.stream
在这里插入图片描述
此时,我们发现ping没有内容
同时,我们往输入框输入http://localhost:8001/hystrix.stream
在这里插入图片描述

在这里插入图片描述

  • 我们发现一直是Loading状态,这是因为我们把在之前把hystrix熔断设置到了consumer了,所以,需要看到内容,我们需要对@HystrixCommand(fallbackMethod = “processHystrix_Get”)放开注释
    在这里插入图片描述
    重复以上步骤,同时访问:http://localhost:8001/dept/get/1
    成功实现监控。
    在这里插入图片描述
    在这里插入图片描述

13、Zuul 路由网关

  • Zuul 是 Netflix 开源的微服务网关,可以对发送到服务端的请求进行一些预处理,比如安全验证、动态路由、负载分配等。
    git地址:https://github.com/Netflix/zuul

13.1、创建microservicecloud-zuul-gateway-9527子模块

  • 填写pom文件所需依赖
<dependencies>
		<!-- zuul路由网关 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-zuul</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-eureka</artifactId>
		</dependency>
		<!-- actuator监控 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		<!-- hystrix容错 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-hystrix</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-config</artifactId>
		</dependency>
		<!-- 日常标配 -->
		<dependency>
			<groupId>com.sc.springcloud</groupId>
			<artifactId>microservicecloud-api</artifactId>
			<version>${project.version}</version>
		</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>
  • 创建主启动类Zuul_9527_StartSpringCloudApp
package com.sc.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@SpringBootApplication
@EnableZuulProxy
public class Zuul_9527_StartSpringCloudApp {
	public static void main(String[] args) {
		SpringApplication.run(Zuul_9527_StartSpringCloudApp.class, args);
	}
}

  • host文件添加地址映射
127.0.0.1 	 myzuul.com
  • 添加配置文件
server: 
  port: 9527
 
spring: 
  application:
    name: microservicecloud-zuul-gateway
 
eureka: 
  client: 
    service-url: 
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka  
  instance:
    instance-id: gateway-9527.com
    prefer-ip-address: true 


info:
  app.name: sc-microcloud
  company.name: www.sc.com
  build.artifactId: $project.artifactId$
  build.version: $project.version$

启动eureka7001、7002、7003、8001hystrix、zuul等

启用路由访问:http://myzuul.com:9527/microservicecloud-dept/dept/get/1
此时,路径中microservicecloud-dept代表provider对应的微服务名
在这里插入图片描述

  • 在application.xml中添加配置以达到访问时无需添加provider对应的微服务名
zuul: 
  #ignored-services: microservicecloud-dept #单个用具体的,多个用* 号
  ignored-services: "*"
  routes: 
    mydept.serviceId: microservicecloud-dept
    mydept.path: /**

访问:http://myzuul.com:9527/dept/get/1
在这里插入图片描述

到这里算是简单完成了一个微服务框架。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值