1、SpringColud简介:
Spring Cloud是一系列框架的有序集合。是利用Spring Boot的开发便利性,巧妙地简化了分布式系统基础设施的开发:例如:服务注册、配置中心、消息总线、负载均衡、断路器、数据监控等等,都可以用Spring Boot的开发风格做到一键启动和部署;
SpringCould开发时创建的子项目一般分为两大类:一类是对SpringBoot框架的抽象和封装;第二类是开发了一部分分布式系统的基础设施的实现。
一般情况下都是使用第一类子项目进行开发已经足够使用。【注:SpringColud详细介绍】
2、SpringCould开发依赖包引入及依赖包版本管理【pom.xml】:
此处要注意的是SpringCould版本和SpringBoot版本要相互兼容,例如:在此项目中兼容版本分别是springBoot-2.0.4 和 SpringCouldFinchley.SR1是相互兼容的。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>SpringCloud</groupId>
<artifactId>SpringCloudDemo01</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>user-services</module>
<module>Eureka-service</module>
<module>consumer-server</module>
</modules>
<packaging>pom</packaging> <!--父级项目pom.xml中的配置-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/>
</parent>
<!--版本属性配置-->
<properties>
<spring-cloud.version>Finchley.SR1</spring-cloud.version>
<mapper.version>2.0.3</mapper.version>
<mysql.version>5.1.46</mysql.version>
<lombok.version>1.18.6</lombok.version>
</properties>
<!--dependencyManagement标签中引入的依赖,子工程还需要手动引入-->
<dependencyManagement>
<dependencies>
<!--springCloud-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--通用Mapper启动器-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>${mapper.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<!--lombok,父类及子类项目中都能使用-->
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies>
<!--springBoot插件-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.book</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3、SpringCould系项目创建
此处练习使用创建了服务提供者子项目:user-Services、注册中心:Eureka-service服务、服务消费者:consumer-service。
项目结构如下:
3.1、服务提供者:user-services
服务提供者功能:实现与数据库的交互。
3.1.1、服务提供者依赖包【pom.xml】:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>SpringCloudDemo01</artifactId>
<groupId>SpringCloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>user-services</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
</dependency>
<!--注册中心客户端依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
</project>
此处引入了注册客户端的依赖:spring-cloud-starter-netflix-eureka-client,用于向注册中心注册服务,用于消费者调用。
3.1.2、服务提供者配置文件【application.yaml】:
server:
port: 8088
spring:
#服务名称
application:
name: user-services
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis
username: root
password: root
mybatis:
type-aliases-package: SpringBoot.Starter.Pojo
eureka:
client:
service-url:
#此处如果需要注册到多个Eureka时,以逗号相隔http://127.0.0.1:8888/eureka,http://127.0.0.1:8899/eureka
defaultZone: http://127.0.0.1:8888/eureka
instance:
prefer-ip-address: true
ip-address: 127.0.0.1
#心跳间隔--服务续约间隔
lease-renewal-interval-in-seconds: 30
#服务的失效时间
lease-expiration-duration-in-seconds: 90
3.1.3、启动入口文件【SpringBootApplicationDemo.java】:
package SpringBoot.Starter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import tk.mybatis.spring.annotation.MapperScan;
/**
* @EnableDiscoveryClient : 使用此注解是实现服务注册功能,包含@EnableEurekaClient注解,开启Eureka注册
*/
@EnableDiscoveryClient
@SpringBootApplication
@MapperScan("SpringBoot.Starter.Mapper")
public class SpringBootApplicationDemo {
public static void main(String[] args) {
SpringApplication.run(SpringBootApplicationDemo.class);
}
}
此文件注解 @EnableDiscoveryClient 就是进行服务注册使用,此注解包含多种注册机制,包含上述Eureka注册服务,当然也可以直接使用Eureka的注解 @EnableEurekaClient 。
注解 @MapperScan(“SpringBoot.Starter.Mapper”) 是与mybatis中的持久层文件扫描配置一样,扫描指定包下的持久层文件,方便容器进行管理;此注解是依赖包通用Mapper启动器中提供:tk.mybatis mapper-spring-boot-starter ,提供了单表的查询,单表操作不用.xml文件。
3.1.4、持久层文件【UserMapper.java】:
package SpringBoot.Starter.Mapper;
import SpringBoot.Starter.Pojo.UserPojo;
import tk.mybatis.mapper.common.Mapper;
public interface UserMapper extends Mapper<UserPojo> {
}
3.1.5、封装实体类【UserPojo.java】:
package SpringBoot.Starter.Pojo;
import lombok.Data;
import tk.mybatis.mapper.annotation.KeySql;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
import java.util.Date;
@Data
@Table(name = "user")
public class UserPojo {
/**
* 此处要注意属性要与表中字段完全一致,并且需要注意的是类型使用封装类型
*/
@Id
@KeySql(useGeneratedKeys = true)
private Integer id;
private String username;
private String password;
private Date birthday;
private Character sex;
private String address;
//备注
private String content;
//备注2
@Transient //不需要持久化到数据库,该字段不必要在表中存在
private String content2;
}
3.1.6、Service层实现类【UserService .java】:
package SpringBoot.Starter.Service;
import SpringBoot.Starter.Mapper.UserMapper;
import SpringBoot.Starter.Pojo.UserPojo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public UserPojo queryUserInfoById(int id){
UserPojo user = userMapper.selectByPrimaryKey(id);
return user;
}
}
3.1.7、控制器类【ControllerDemo01.java】:
package SpringBoot.Starter.Controller;
import SpringBoot.Starter.Pojo.UserPojo;
import SpringBoot.Starter.Service.UserService;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/user")
public class ControllerDemo01 {
@Autowired
private UserService userService;
@GetMapping("{id2}")
public UserPojo queryUserInfoController(@PathVariable int id2){
UserPojo userPojo = userService.queryUserInfoById(id2);
return userPojo;
}
}
restdful请求: @GetMapping("{id2}")。
3.2、注册中心服务【Eureka-service】:
注册服务,为Eureka客户端提供注册服务,使用的Eureka依赖包是:spring-cloud-starter-netflix-eureka-server
3.2.1、依赖包配置【pom.xml】:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>SpringCloudDemo01</artifactId>
<groupId>SpringCloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Eureka-service</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>
</dependencies>
</project>
3.2.2、配置文件【application.yaml】:
server:
port: 8888
#服务名称
spring:
application:
name: eureka-service
#注册中心访问路径配置
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8888/eureka
#是否注册自己
#register-with-eureka: false
##指定ip,否则联网时获取的ip可能不能正常访问
instance:
ip-address: 127.0.0.1
prefer-ip-address: true
#服务失效剔除的时间间隔
server:
eviction-interval-timer-in-ms: 30000
#注册机制的自我保护机制,默认是开启状态,默认状态,在一定情况下(例如网络不稳定(会进行自我判断)时)服务失效时也不会马上剔除服务
#enable-self-preservation: true
此处配置扩展了注册开关(是否注册自己,注册服务默认是会注册自己的)、注册服务的自我保护机制、服务失效剔除时间、指定注册、请求的ip信息。
3.2.3:启动入口文件【SpringCloudEurekaService.java】:
package EurekaService.Application;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* @EnableEurekaServer : Spring Cloud 注册服务注解
*/
@EnableEurekaServer
@SpringBootApplication
public class SpringCloudEurekaService {
public static void main(String[] args) {
SpringApplication.run(SpringCloudEurekaService.class);
}
}
注解:@EnableEurekaServer 此注解用于注册服务。
3.3、服务消费者【consumer-service】:
主要是获取调用注册服务中已注册成功的服务。
3.3.1、依赖包配置【pom.xml】:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>SpringCloudDemo01</artifactId>
<groupId>SpringCloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>consumer-server</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--Ribbon负载均衡:需要注意的是引入的一定要是注册中心Eureka的riboon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-colud-starter-netflix-eureka-ribbon</artifactId>
</dependency>
</dependencies>
</project>
服务消费者服务一般会用到负载均衡器,此配置文件中引入了负载均衡器的依赖包Ribbon,
<!--Ribbon负载均衡:需要注意的是引入的一定要是注册中心Eureka的riboon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-colud-starter-netflix-eureka-ribbon</artifactId>
</dependency>
3.3.2、配置文件【application.yaml】:
server:
port: 8080
spring:
application:
name: consumer-service
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8888/eureka
#服务获取时间间隔
registry-fetch-interval-seconds: 30
instance:
prefer-ip-address: true
ip-address: 127.0.0.1
#使用服务id指定哪个服务使用哪种负载均衡方式 -- 配置默认使用随机数
user-services:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
服务消费者服务一般会用到负载均衡器,此配置文件中可以通过服务提供者ID对负载负载均衡器的默认规则进行制定:
#使用服务id指定哪个服务使用哪种负载均衡方式 -- 配置默认使用随机数
user-services:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
3.3.3、启动入口文件【SpringCloudApplicationDemo01.java】:
package SpringCloudApplication;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@EnableDiscoveryClient
@SpringBootApplication
public class SpringCloudApplicationDemo01 {
public static void main(String[] args) {
SpringApplication.run(SpringCloudApplicationDemo01.class);
}
@Bean
@LoadBalanced
public RestTemplate restTemplateDem01(){
return new RestTemplate();
}
}
在RestTemplate 中使用注解@LoadBalanced,引入了负载均衡器,此处使用注解只是使用负载均衡器的一种方式。
3.3.4、封装类【UserModel.java】:
package SpringCloudApplication.Pojo;
import lombok.Data;
import java.util.Date;
@Data
public class UserModel {
private Integer id;
private String username;
private String password;
private Date birthday;
private Character sex;
private String address;
//备注
private String content;
}
3.3.5、控制器类【ControllerDem01.java】:
package SpringCloudApplication.Controller;
import SpringCloudApplication.Pojo.UserModel;
import com.sun.org.apache.xerces.internal.util.SynchronizedSymbolTable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
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;
@RestController //相当于@Controller和@ResponseBody
@RequestMapping("/query")
public class ControllerDem01 {
@Autowired
private RestTemplate restTemplate;
/**
*
*/
/*@Autowired
private DiscoveryClient discoveryClient;*/
/**
* 使用ribbon负载均衡器获取服务 -- 默认使用轮询的方式
*
* 还有一种负载均衡器的配置使用方式是在RestTemplate创建时使用注解@LoadBalanced -- 默认使用随机的方式实现负载均衡
*/
/*@Autowired
private LoadBalancerClient c;*/
@GetMapping("{id}")
public UserModel queryUserInfoByRestTemplate(@PathVariable int id){
//通过服务ID获取实例
/*List<ServiceInstance> list = discoveryClient.getInstances("user-services");
//从获取的实例中获取IP和端口
ServiceInstance serviceInstance = list.get(0);
String url = serviceInstance.getHost();
int port = serviceInstance.getPort();
System.out.println(")))))))))))))))))))))))))))))))))))))"+"http://"+url+":"+port+"/user/"+id);
UserModel user = restTemplate.getForObject("http://"+url+":"+port+"/user/"+id,UserModel.class);*/
/**
* http://xingfu:8088/user/42
* 注意:使用上述请求地址时一定要断网,否则无法通过本机计算机名访问
* 所以要在配置文件 application.yaml 中指定ip,配置信息如下:
* #注册中心访问路径配置
* eureka:
* client:
* service-url:
* defaultZone: http://127.0.0.1:8888/eureka
* ##指定ip,否则联网时获取的ip可能不能正常访问
* instance:
* ip-address: 127.0.0.1
* prefer-ip-address: true
*
*
* 结果:
* {"id":42,"username":"小二王","password":"123","birthday":"2018-03-02T07:09:37.000+0000","sex":"女","address":"北京金燕龙","content":null}
*/
/**
* 负载均衡器获取服务提供者信息
* 负载均衡的方式:随机、轮询、hashCode、。。。。
*/
/*ServiceInstance serviceInstance = c.choose("user-services");
String ip = serviceInstance.getHost();
int port = serviceInstance.getPort();
String url = "http://"+ip+":"+port+"/user/"+id;
System.out.println("----------------------"+url);
UserModel user = restTemplate.getForObject(url, UserModel.class);*/
/**
* 使用注解配置实现负载均衡
*/
String url = "http://user-services/user/"+id;
System.out.println("----------------------"+url);
UserModel user = restTemplate.getForObject(url,UserModel.class);
/*String url = "http://localhost:8088/user/"+id;
UserModel user = restTemplate.getForObject(url,UserModel.class);*/
return user;
}
}
在此处使用了多两种负载均衡器的使用方法和多种服务调用方式。
注:服务的高可用性启动配置: