Spring Cloud Netflix入门
在上一篇文章说到,SpringCloud基于微服务的诞生的产品,其实这样说也不准确。更准确的说法是应该是SpringCloud是Spring官方对微服务制订的一个标准(规范)。
而基于SpringCloud这套标准,在业界诞生了两款优秀的产品,SpringCloudNetflix和SpringCloudAlibaba。
既然SpringCloud是Spring官方提出的,那么构建SpringCloud项目必然要跟Spring的其它的孵化产品有着千丝万缕的关系。
SpringCloud构建于SpringBoot之上,使得开发者很容易入手并快速应用于生产中。利用SpringBoot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用SpringBoot的开发风格做到一键启动和部署。
SpringBoot与SpringCloud的关系
SpringBoot为SpringCloud提供了代码实现环境
SpringCloud是基于SpringBoot的微服务系统架构的一站式解决方案
常用的SpringCloud资源网站
SpringCloud官网
https://spring.io/projects/spring-cloud
SpringCloud中文网
https://www.springcloud.cc/
SpringCloud版本号
SpringCloud版本号不是常见的数字版本号而是一些单词(英国伦敦地铁站站名)SpringCloud要求必须要运行在某一特定SpringBoot版本下,在官网上可以看见对应版本说明。我们选择比较稳定的Hoxton版本进行讲解。
父工程+提供者&消费者项目
创建父工程并实现一个消费者调用提供者的实例,为后续SpringCloud项目的运行提供测试环境。
使用了MySQL数据库
使用SpringDataJPA作为持久层技术
没有用到SpringCloud
创建工程
打开IDEA点击创建新的工程
点击Next,给项目取名,JavaVersion选择8:
在选择依赖的界面什么都不选,直接点击Next,最后指定存储位置,finish结束。
familycloud项目作为本教程的父工程。
修改pom.xml文件
由于SpringCloud使用Hoxton版本,所以要将SpringBoot的版本改成对应的2.2.X/2.3.X版本(这里使用的是2.2.2.RELEASE),可以删除一些项目自动生成的不需要的依赖并对后续所要使用的依赖进行版本管理:
<?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> <packaging>pom</packaging> <modules> <module>provider-8081</module> <module>consumer-8080</module> </modules> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.2.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.familycloud</groupId> <artifactId>familycloud</artifactId> <version>0.0.1-SNAPSHOT</version> <name>familycloud</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <druid.version>1.1.10</druid.version> <mysql.version>8.0.18</mysql.version> <lombok.version>1.18.20</lombok.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>${druid.version}</version> </dependency> </dependencies> </dependencyManagement> </project>1234567891011121314151617181920212223242526272829303132333435363738394041424344454647复制代码类型:[java]
创建提供者工程(子工程provider-8081)
右键familycloud文件夹点击New-Module创建提供者工程。左侧边栏选择Maven直接点击Next,给项目取名后,JavaVersion选择8:
在选择依赖的界面什么都不选,直接点击Next,最后指定存储位置,finish结束。
添加需要的依赖
将提供者工程需要的依赖添加到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>familycloud</artifactId> <groupId>com.familycloud</groupId> <version>0.0.1-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>provider-8081</artifactId> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> </project>123456789101112131415161718192021222324252627282930313233343536复制代码类型:[java]
定义实体类
定义实体类的同时,使用@Entity标签在数据库中自动创建Pets表
package com.javafamily.provider8081.bean;import com.fasterxml.jackson.annotation.JsonIgnoreProperties;import lombok.Data;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;@Data// 使用自动建表@Entity// 不需要转化为json的属性 @JsonIgnoreProperties({"hibernateLazyInitializer", "handler", "fieldHandler"})public class Pets { // 表示当前属性为自动建的表的主键 @Id // 主键自动递增 @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String name; }1234567891011121314151617181920212223复制代码类型:[java]
客户端和服务端之间通过JSON数据完成通信,而Java对象和JSON数据间的转换是由HttpMessageConverter接口完成的(其中的Jackson类用来完成Java对象和JSON数据间的转换)
JPA默认实现是Hibernate,Hibernate默认对于对象的查询是基于延迟加载。
延迟加载
// 当前要访问id为5的对象,底层应该调用select语句,但是此时没有真正调用//所以这里的pets实际是一个javasist动态代理对象,是空的,如果被数据转换将会报错Pets pets = service.findById(5);// 访问详情时才会真正调用select语句String name = pets.getName();123456789复制代码类型:[java]
因此需要使用@JsonIgnoreProperties标签将延迟加载关闭。
定义Repository接口继承JpaRepository使该接口提供JPA的相关功能:
package com.javafamily.provider8081.repository;import com.javafamily.provider8081.bean.Pets;import org.springframework.data.jpa.repository.JpaRepository;// 第一个泛型是,当前Repository所操作的对象的类型// 第二个泛型是,当前Repository所操作的对象的id类型public interface PetsRepository extends JpaRepository<Pets, Integer> { }12345678910复制代码类型:[java]
JpaRepository对关系型数据库进行了抽象封装继承了PagingAndSortingRepository类的所有方法和QueryByExampleExecutor的相关方法。
JpaRepository的实现类是SimpleJpaRepository。
支持了QueryByExample、批量删除、提高删除效率、手动刷新数据库的更改方法,将默认实现的查询结果变成List。
再定义service接口和service实现类(增删改查):
package com.javafamily.provider8081.service;import com.javafamily.provider8081.bean.Pets;import java.util.List;public interface PetsService { boolean savePets(Pets pets); boolean removePetsById(Integer id); boolean modifyPets(Pets pets); Pets getPetsById(int id); List<Pets> listAllPets(); }12345678910111213141516复制代码类型:[java]
添加数据
@Servicepublic class PetsServiceImpl implements PetsService { @Autowired private PetsRepository repository; @Override public boolean savePets(Pets pets) { Pets obj = repository.save(pets); return obj != null ? true : false; } }123456789101112复制代码类型:[java]
添加数据根据id的不同,有三种情况:
pets的id为null,执行插入操作
pets的id不为null,数据库中有该id存在,执行修改操作
pets的id不为null,数据库中没有该id,执行插入操作
删除数据
@Override public boolean removePetsById(Integer id) { if (repository.existsById(id)) { // 在数据库中指定的id若不存在,该方法会抛出异常 repository.deleteById(id); return true; } return false; }123456789复制代码类型:[java]
修改数据
@Override public boolean modifyPets(Pets pets) { Pets obj = repository.save(pets); return obj != null ? true : false; }12345复制代码类型:[java]
查询数据
// 根据id查询 @Override public Pets getPetsById(int id) { if (repository.existsById(id)) { // 在数据库中指定的id若不存在,该方法会抛出异常 return repository.getOne(id); } Pets pets = new Pets(); pets.setName("dog"); return pets; } // 查询所有 @Override public List<Pets> listAllPets() { return repository.findAll(); }1234567891011121314151617复制代码类型:[java]
最后定义处理器:
package com.javafamily.provider8081.controller;import com.javafamily.provider8081.bean.Pets;import com.javafamily.provider8081.service.PetsService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;import java.util.List;@RestController@RequestMapping("/pets")public class PetsController { @Autowired private PetsService petsService; @PostMapping("/save") public boolean saveHandler(@RequestBody Pets pets) { return petsService.savePets(pets); } @DeleteMapping("/delete/{id}") public boolean delHandler(@PathVariable("id") Integer id) { return petsService.removePetsById(id); } @PutMapping("/update") public boolean updateHandler(@RequestBody Pets pets) { return petsService.modifyPets(pets); } @GetMapping("/get/{id}") public Pets getHandler(@PathVariable("id") Integer id) { return petsService.getPetsById(id); } @GetMapping("/list") public List<Pets> listHandler() { return petsService.listAllPets(); } }12345678910111213141516171819202122232425262728293031323334353637383940复制代码类型:[java]
执行代码可以看到cloudfamily数据库中的pets表已经自动生成:
在postman中进行测试,增删改查功能都可以使用。
创建消费者工程(子工程consumer-8080)
与创建提供者工程的步骤相同,创建提供者工程,添加需要的依赖:
<?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>familycloud</artifactId> <groupId>com.familycloud</groupId> <version>0.0.1-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>consumer-8080</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies> </project>123456789101112131415161718192021222324复制代码类型:[java]
定义实体类:
package com.javafamily.consumer8080.bean;import lombok.Data;@Datapublic class Pets { private Integer id; private String name; }123456789复制代码类型:[java]
定义PetsConfigure容器类:
package com.javafamily.consumer8080.configure;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.client.RestTemplate;@Configurationpublic class PetsConfigure { @Bean public RestTemplate restTemplate() { return new RestTemplate(); } }12345678910111213复制代码类型:[java]
RestTemplate提供了常见的REST请求方案的模版(GET、POST、PUT、DELETE)
RestTemplate继承自InterceptingHttpAccessor并且实现了RestOperations接口,其中RestOperations接口定义了基本的RESTful操作。
最后定义处理器:
package com.javafamily.consumer8080.controller;import com.javafamily.consumer8080.bean.Pets;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;import org.springframework.web.client.RestTemplate;import java.util.List;@RestController@RequestMapping("/pets")public class PetsController { @Autowired private RestTemplate restTemplate; private static final String SERVICE_PROVIDER = "http://localhost:8081"; @PostMapping("/save") public boolean saveHandler(@RequestBody Pets pets) { // 消费者连接提供者端口号 String url = SERVICE_PROVIDER + "/pets/save"; return restTemplate.postForObject(url, pets, Boolean.class); } @DeleteMapping("/delete/{id}") public void deleteHandler(@PathVariable("id") int id) { // 消费者连接提供者端口号 String url = SERVICE_PROVIDER + "/pets/delete/" + id; restTemplate.delete(url); } @PutMapping("/update") public void updateHandler(@RequestBody Pets pets) { // 消费者连接提供者端口号 String url = SERVICE_PROVIDER + "/pets/update"; restTemplate.put(url, pets); } @GetMapping("/get/{id}") public Pets getByIdHandler(@PathVariable("id") int id) { // 消费者连接提供者端口号 String url = SERVICE_PROVIDER + "/pets/get/" + id; return restTemplate.getForObject(url, Pets.class); } @GetMapping("/list") public List<Pets> listHandler() { // 消费者连接提供者端口号 String url = SERVICE_PROVIDER + "/pets/list"; return restTemplate.getForObject(url, List.class); } }12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455复制代码类型:[java]
运行代码,增删改查功能都可以使用。
从本篇起,每节的代码都会上传到gitee
https://gitee.com/javainfamily/spring-cloud