SpringCloud简介
SpringCloud是一系列框架的有序集合,它利用SpringBoot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用SpringBoot的开发风格做到一键启动和部署。SpringCloud并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过SpringBoot风格进行再封装屏,蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。
详细介绍: https://baike.so.com/doc/25751000-26884657.html
配套参考资料:
springcloud项目官方主页:https://projects.spring.io/spring-cloud
springcloud中文网(有很详细的翻译文档):https://springcloud.cc
springcloud中文论坛:http://springcloud.cn
SpringCloud入门案例(使用的是jpa)
使用SpringBoot开发项目的好处在于能够快速的开发单体项目,很多框架整合无需配置,极大的提高了开发效率。使用SpringBoot开发项目依然属于传统的开发模式,因为所有的代码都写在一个工程内。
Mvc模式相信已经被大家所熟知,Mvc模式是为了使代码层次分明,便于维护,提高代码的健壮性;当项目过于臃肿的话,MVC模式的项目依然难于维护。而SpringCloud作为分布式服务技术的代表,其实就是对MVC模式的一种延伸。将整个项目的model层、dao层、service层、controller层等等进行拆分,使其独立出来成为一个单独的项目,解决由于项目过于臃肿不便于维护所带来的一系列问题。
最简单的微服务架构会有四个工程:
父工程:microservice(主要就是一个pom,用于管理module,以及管理依赖,规范所有jar包版本等)
通用模块(M):microservice-common(主要是放一些其他项目公用的东西,比如实体类,工具类等等)
服务提供者(C):microservice-student-provider-1001(用于操作数据库并且被浏览器所访问)
服务消费者(C):microservice-student-consumer-80(用于通过restful api来调用服务提供者的接口)
微服务架构注意点:
1、SpringBoot、SpringCloud版本在父工程定义
2、由于通用模块无需操作数据库,但SpringBoot项目启动是默认会读取数据库,所以得在启动类添加以下注解@SpringBootApplication(exclude={DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
3、分布式jpa需要在启动类上添加@EntityScan("com.ue.entity")跟@EnableJpaRepositories("com.ue.repository")
4、消费者需要添加配置类获取org.springframework.web.client.RestTemplate,因为SpringCloud底层是通过RestTemplate来调用服务提供者提供的服务的
传统项目拆分成微服务架构图如下:
创建父工程(microservice)
父工程是一个maven项目,用一般创建方式即可,父工程的主要用途是锁定pom依赖包版本。由于springcloud2.x停止更新,这里我们采用稳定的低版本,配套的springboot版本为1.x版本
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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ue</groupId>
<artifactId>microservice</artifactId>
<version>1.0-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>
<!--锁定pom依赖jar包版本,但并不实际引用(即用于继承)-->
<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-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
创建通用模块(microservice-common)
通用模块主要存放实体类、工具包等被整个微服务框架所使用的代码,创建一个简单的springboot模块即可,相关代码如下
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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.ue</groupId>
<artifactId>microservice</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>microservice-common</artifactId>
<dependencies>
<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>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
MicroserviceCommonApplication.java:
package com.ue;
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 MicroserviceCommonApplication {
public static void main(String[] args) {
SpringApplication.run(MicroserviceCommonApplication.class, args);
}
}
Student.java:
package com.ue.entity;
import javax.persistence.*;
import java.io.Serializable;
@Entity
@Table(name = "t_springcloud_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;
}
}
创建服务提供者(microservice-student-provider-1001)
创建一个简单的springboot模块,这里需要操作数据库并且被浏览器所访问,故需要添加相关代码如下
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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.ue</groupId>
<artifactId>microservice</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>microservice-student-provider-1001</artifactId>
<dependencies>
<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>
<version>1.1.10</version>
</dependency>
<!-- 修改后立即生效,热部署 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>com.ue</groupId>
<artifactId>microservice-common</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</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/demosite1?useUnicode=true&characterEncoding=utf8
username: root
password: root
jpa:
hibernate:
ddl-auto: update
show-sql: true
MicroserviceStudentProvider1001Application.java:
package com.ue;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@SpringBootApplication
@EntityScan("com.ue.entity")
@EnableJpaRepositories("com.ue.repository")
public class MicroserviceStudentProvider1001Application {
public static void main(String[] args) {
SpringApplication.run(MicroserviceStudentProvider1001Application.class, args);
}
}
StudentRepository.java:
package com.ue.repository;
import com.ue.entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface StudentRepository extends JpaRepository<Student, Integer>, JpaSpecificationExecutor<Student> {
}
StudentService.java:
package com.ue.service;
import com.ue.entity.Student;
import java.util.List;
/**
* 学生信息Service接口
* @author Administrator
*/
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);
}
StudentServiceImpl.java:
package com.ue.service.impl;
import java.util.List;
import javax.annotation.Resource;
import com.ue.entity.Student;
import com.ue.repository.StudentRepository;
import com.ue.service.StudentService;
import org.springframework.stereotype.Service;
/**
* 学生信息Service实现类
* @author Administrator
*/
@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);
}
}
StudentProviderController.java:
package com.ue.controller;
import java.util.List;
import javax.annotation.Resource;
import com.ue.entity.Student;
import com.ue.service.StudentService;
import org.springframework.web.bind.annotation.*;
/**
* 服务提供者-学生信息控制器
* @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;
}
}
}
创建服务消费者(microservice-student-consumer-80)
服务消费者主要是通过restful api来调用服务提供者的接口,故不需要操作数据库,相关配置如下
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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.ue</groupId>
<artifactId>microservice</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>microservice-student-consumer-80</artifactId>
<dependencies>
<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>
<dependency>
<groupId>com.ue</groupId>
<artifactId>microservice-common</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
application.yml:
server:
port: 80
context-path: /
MicroserviceStudentConsumer80Application.java:
package com.ue;
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 MicroserviceStudentConsumer80Application {
public static void main(String[] args) {
SpringApplication.run(MicroserviceStudentConsumer80Application.class, args);
}
}
SpringCloudConfig.java:
package com.ue.config;
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();
}
}
StudentConsumerController.java:
package com.ue.controller;
import java.util.List;
import javax.annotation.Resource;
import com.ue.entity.Student;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
/**
*
* @author Administrator
*
*/
@RestController
@RequestMapping("/student")
public class StudentConsumerController {
@Resource
private RestTemplate restTemplate;
/**
* 添加或者修改学生信息
* @param student
* @return
*/
@PostMapping(value="/save")
private boolean save(@RequestBody Student student){
return restTemplate.postForObject("http://localhost:1001/student/save", student, Boolean.class);
}
/**
* 查询学生信息
* @return
*/
@GetMapping(value="/list")
public List<Student> list(){
return restTemplate.getForObject("http://localhost:1001/student/list", List.class);
}
/**
* 根据id查询学生信息
* @return
*/
@GetMapping(value="/get/{id}")
public Student get(@PathVariable("id") Integer id){
return restTemplate.getForObject("http://localhost:1001/student/get/"+id, Student.class);
}
/**
* 根据id删除学生信息
* @return
*/
@GetMapping(value="/delete/{id}")
public boolean delete(@PathVariable("id") Integer id){
try{
restTemplate.getForObject("http://localhost:1001/student/delete/"+id, Boolean.class);
return true;
}catch(Exception e){
return false;
}
}
}
测试时先启动服务提供者再启动服务消费者,部分测试结果如下:
注意:用postman测试新增接口的时候,服务提供端的实体参数前面要加上@RequestBody注解,否则会接收不到数据