SpringCloud 为开发人员提供了快速构建分布式系统的一些工具,包括配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等。它运行环境简单,可以在开发人员的电脑上跑。
Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。Spring Cloud并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。
微服务架构的应用场景:
1、系统拆分,多个子系统
2、每个子系统可部署多个应用,应用之间负载均衡实现
3、需要一个服务注册中心,所有的服务都在注册中心注册,负载均衡也是通过在注册中心注册的服务来使用一定策略来实现。
4、所有的客户端都通过同一个网关地址访问后台的服务,通过路由配置,网关来判断一个URL请求由哪个服务处理。请求转发到服务上的时候也使用负载均衡。
5、服务之间有时候也需要相互访问。例如有一个用户模块,其他服务在处理一些业务的时候,要获取用户服务的用户数据。
6、需要一个断路器,及时处理服务调用时的超时和错误,防止由于其中一个服务的问题而导致整体系统的瘫痪。
7、还需要一个监控功能,监控每个服务调用花费的时间等。
Spring Cloud的优势
- 产出于spring大家族,spring在企业级开发框架中无人能敌,来头很大,可以保证后续的更新、完善。比如dubbo现在就差不多死了
- 有spring Boot 这个独立干将可以省很多事,大大小小的活spring boot都搞的挺不错。
- 作为一个微服务治理的大家伙,考虑的很全面,几乎服务治理的方方面面都考虑到了,方便开发开箱即用。
- Spring Cloud 活跃度很高,教程很丰富,遇到问题很容易找到解决方案
- 轻轻松松几行代码就完成了熔断、均衡负责、服务中心的各种平台功能
二、服务提供者与消费关系
服务提供者:提供服务被人调用
消费者:调用被人服务
https://projects.spring.io/spring-cloud/ springcloud项目官方主页
https://springcloud.cc/ springcloud中文网 有很详细的翻译文档
http://springcloud.cn/ springcloud中文论坛
新建一个working set
定义抽象的父类
我们开发项目,现在基本都用到maven,以及用父子项目,以及公共模块依赖,来构建方便扩展的项目体系;
首先我们建立父项目 microservice ,主要是一个pom,管理module,以及管理依赖,规范所有jar包版本等;
父模块
定义编码和编译版本compiler,druid阿里巴巴连接池
dependencyManagement 依赖管理,父项目加了依赖管理,子项目可以直接加groupId和artifactId用,不需要加版本
scope import直接引入了公共的pom
<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.springcloud</groupId>
<artifactId>microservice</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>
<druid.version>1.1.10</druid.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Edgware.SR4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.13.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<modules>
<module>microservice-common</module>
<module>microservice-student-provider-1001</module>
<module>microservice-student-consumer-80</module>
</modules>
</project>
公共模块的搭建,分布式该抽象的都抽象出来
我们新建module公共模块项目 microservice-common,主要是放一些其他项目公用的东西,比如实体类,工具类等等;
新建module模块
作为一个module了
不用指定版本,父模块已经指定了版本
<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.springcloud</groupId>
<artifactId>microservice</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>microservice-common</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
</dependencies>
</project>
建立实体类序列化,进行对象服务调用必须序列化才能传输。当然我们数据库里也提前建一个db_springcloud数据库;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* 学生信息实体
* @author Administrator
*
*/
@Entity
@Table(name="t_student")
public class Student implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
private Integer id; // 编号
@Column(length=50)
private String name; // 姓名
@Column(length=50)
private String grade; // 年级
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGrade() {
return grade;
}
public void setGrade(String grade) {
this.grade = grade;
}
}
其他的子项目还要引入依赖,要maven install一下,相当于打个jar包发布到本地仓库
分布式就是消费者调用提供者实现解耦
microservice-student-provider-1001服务提供者项目建立
我们新建一个服务器提供者module子模块,类似前面建的common公共模块,名称是 microservice-student-provider-1001
项目-某个模块-提供者-端口(服务集群和负载均衡要分多个端口)
加common项目依赖,以及 springboot的 web jpa 驱动包 tomcat 连接池 配置 包括自动热部署配置,要依赖公共的模块,需要common里面的entity。都不需要版本,都依赖父类
<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.springcloud</groupId>
<artifactId>microservice</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>microservice-student-provider-1001</artifactId>
<dependencies>
<dependency>
<groupId>com.java.springcloud</groupId>
<artifactId>microservice-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</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: 1001
context-path: /
# 数据源配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/db_springcloud
username: root
password: 123456
jpa:
hibernate:
ddl-auto: update
show-sql: true
接口
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import com.entity.Student;
/**
* 学生Repository接口
* @author Administrator
*
*/
public interface StudentRepository extends JpaRepository<Student, Integer>,JpaSpecificationExecutor<Student>{
}
import java.util.List;
import com.entity.Student;
public interface StudentService {
/**
* 添加或者修改学生信息
* @param student
*/
public void save(Student student);
/**
* 根据id查找学生信息
* @param id
* @return
*/
public Student findById(Integer id);
/**
* 查询学生信息
* @return
*/
public List<Student> list();
/**
* 根据id删除学生信息
* @param id
*/
public void delete(Integer id);
}
实现层
@Service("studentService")为bean的注解
save方法有id修改,无id为添加
import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import com.entity.Student;
import com.repository.StudentRepository;
import com.service.StudentService;
@Service("studentService")
public class StudentServiceImpl implements StudentService{
@Resource
private StudentRepository studentRepository;
@Override
public void save(Student student) {
studentRepository.save(student);
}
@Override
public Student findById(Integer id) {
return studentRepository.findOne(id);
}
@Override
public List<Student> list() {
return studentRepository.findAll();
}
@Override
public void delete(Integer id) {
studentRepository.delete(id);
}
}
controller
import java.util.List;
import javax.annotation.Resource;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.entity.Student;
import com.service.StudentService;
/**
* 服务提供者-学生信息控制器
* @author Administrator
*
*/
@RestController
@RequestMapping("/student")
public class StudentProviderController {
@Resource
private StudentService studentService;
/**
* 添加或者修改学生信息
* @param student
* @return
*/
@PostMapping(value="/save")
public boolean save(Student student){
try{
studentService.save(student);
return true;
}catch(Exception e){
return false;
}
}
/**
* 查询学生信息
* @return
*/
@GetMapping(value="/list")
public List<Student> list(){
return studentService.list();
}
/**
* 根据id查询学生信息
* @return
*/
@GetMapping(value="/get/{id}")
public Student get(@PathVariable("id") Integer id){
return studentService.findById(id);
}
/**
* 根据id删除学生信息
* @return
*/
@GetMapping(value="/delete/{id}")
public boolean delete(@PathVariable("id") Integer id){
try{
studentService.delete(id);
return true;
}catch(Exception e){
return false;
}
}
}
启动类,我们运行启动类,自动生成t_student表;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class StudentProviderApplication_1001 {
public static void main(String[] args) {
SpringApplication.run(StudentProviderApplication_1001.class, args);
}
}
http://localhost:1001/student/get/1
服务消费者
我们新建一个服务器提供者module子模块,类似前面建的common公共模块,名称是 microservice-student-consumer-80.
80端口对外的端口
消费者要调用提供者,底层是http rest风格调用
<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.springcloud</groupId>
<artifactId>microservice</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>microservice-student-consumer-80</artifactId>
<dependencies>
<dependency>
<groupId>com.java.springcloud</groupId>
<artifactId>microservice-common</artifactId>
<version>${project.version}</version>
</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>
application.yml配置文件:
server:
port: 80
context-path: /
定义config类,相当于定义一个bean
@Configuration 相当于定义了一个bean,相当于spring或xml配置文件,加了注解其他类都会扫描到。
@Bean controller层要进行注入,直接调用。直接@resource然后@Autowired自动装配
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* SpringCloud相关配置
* @author Administrator
*
*/
@Configuration
public class SpringCloudConfig {
/**
* 调用服务模版对象
* @return
*/
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
save 远程调用服务提供者的save方法
postForObject post方式 地址,请求对象,返回类型
getForObject get方式没有参数
import java.util.List;
import javax.annotation.Resource;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
* 服务消费者-学生信息控制器
* @author Administrator
*
*/
@RestController
@RequestMapping("/student")
public class StudentConsumerController {
@Resource
private RestTemplate restTemplate;
private final static String PRE_HOST="http://localhost:1001";
/**
* 添加或者修改学生信息
* @param student
* @return
*/
@PostMapping(value="/save")
public boolean save(Student student){
return restTemplate.postForObject(PRE_HOST+"/student/save", student, Boolean.class);
}
/**
* 查询学生信息
* @return
*/
@SuppressWarnings("unchecked")
@GetMapping(value="/list")
public List<Student> list(){
return restTemplate.getForObject(PRE_HOST+"/student/list", List.class);
}
/**
* 根据id查询学生信息
* @return
*/
@GetMapping(value="/get/{id}")
public Student get(@PathVariable("id") Integer id){
return restTemplate.getForObject(PRE_HOST+"/student/get/"+id, Student.class);
}
/**
* 根据id删除学生信息
* @return
*/
@GetMapping(value="/delete/{id}")
public boolean delete(@PathVariable("id") Integer id){
return restTemplate.getForObject(PRE_HOST+"/student/delete/"+id, Boolean.class);
}
}
定义启动类
exclude 不会注入数据源和数据库驱动
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
@SpringBootApplication(exclude={DataSourceAutoConfiguration.class,HibernateJpaAutoConfiguration.class})
public class StudentConsumerApplication_80 {
public static void main(String[] args) {
SpringApplication.run(StudentConsumerApplication_80.class, args);
}
}
配置文件
server:
port: 80
context-path: /